laravel/forge-cli
Laravel Forge CLI is the command-line companion for Laravel Forge, letting you provision servers, deploy sites, and manage scheduled jobs, queue workers, and SSL certificates from your terminal.
Forge CLI is a standalone binary, not a package you composer require into your app. Install it globally and treat it as a shell tool that talks to the Forge API and, for some commands, opens SSH sessions to your servers.
composer global require laravel/forge-cli
# make sure ~/.composer/vendor/bin or ~/.config/composer/vendor/bin is on PATH
forge list # every command the installed version exposes
Authenticate once:
forge login # paste an API token from forge.laravel.com/profile/api
# or, for CI and ephemeral containers:
export FORGE_API_TOKEN=...
Then bind a working copy to a site — this is the step everything else keys off:
cd ~/code/my-app
forge init # pick server + site; writes the project's .forge config
First use case worth learning end-to-end is the deploy loop: forge deploy, then forge deploy:logs --follow to stream what actually happened, then forge ssh to land on the box when it fails. That single loop replaces most dashboard round-trips.
Where to look first, in order: forge <command> --help (the CLI is the source of truth for flags), the official docs at forge.laravel.com/docs/cli, and the changelog — this package's releases are short and every entry is a behavioral fix you may be depending on.
Link once, commit the link. forge init writes a small project-local config (a .forge directory) holding the server/site identifiers. It contains no secrets, so committing it means a new teammate runs forge deploy on day one without a "which site is this?" conversation. Monorepos break this assumption — one site per checkout, or re-run init per directory.
Env sync as an explicit, reviewed operation. The env:pull / env:push pair is the highest-value and highest-risk feature:
forge env:pull > .env.remote # inspect, don't blindly pull over .env
diff .env .env.remote
forge env:push # from a reviewed local .env
Adopt a habit of pulling into a scratch file, diffing, and only then pushing. On a team, nobody should be running env:push from a dirty working copy.
CI deploys with a pinned CLI. In GitHub Actions (or any runner), install a fixed version and pass the token via secret — never let the pipeline hit an interactive prompt:
- run: composer global require laravel/forge-cli:^2.0.4
- run: forge deploy
env:
FORGE_API_TOKEN: ${{ secrets.FORGE_API_TOKEN }}
- run: forge deploy:logs --follow
env:
FORGE_API_TOKEN: ${{ secrets.FORGE_API_TOKEN }}
Bake the same version into your CI Docker image so local and pipeline behavior match. Deploy polling is configurable (added in v2.0.3) — tune the interval/timeout when your deploy scripts run long or the API round-trip is slow.
SSH-first debugging. Run forge ssh:configure once and you get host aliases in ~/.ssh/config, so your editor's remote mode, a database GUI, and plain ssh all work without copying IPs. From there:
forge ssh # current project's server
forge ssh --user=forge # specify the remote user
forge site:logs --follow # nginx/php logs, streamed
forge daemon:logs --follow # queue worker output
forge database:shell # needs the database name/credentials
Wrap it, don't memorize it. Put the three or four commands your team actually uses behind a Makefile or Composer script (make deploy, make logs, make ssh). It documents intent and gives you one place to add --follow, --user, or a pinned binary path.
Don't fight Forge's own auto-deploy. If quick-deploy on push is enabled for the branch, a CI forge deploy is a second deploy. Use the CLI for manual/hotfix deploys and pipeline-triggered deploys on branches without push-to-deploy, or turn auto-deploy off entirely and let CI own it.
Post-deploy worker restart. The CLI doesn't do this for you — either call the daemon restart command as a final pipeline step or make sure your deploy script handles queue restarts.
^2.0.4 minimum. v2.0.4 fixed deploy:logs showing an old deployment's log. If you parse deploy output in CI, that bug will silently give you stale results.--follow, not --tail. Renamed back in v0.1.4; old snippets and blog posts still say --tail.FORGE_API_TOKEN support for CI arrived in v1.3.1. Always pass the token via env and any required identifiers as flags; anything that prompts will hang a pipeline.FORGE_API_TOKEN overrides the stored login, so a stale export in your shell profile can point forge deploy at the wrong account's site. Check which token is live before a production deploy.env:push overwrites. It's a full replace of the remote .env, not a merge, and comment/formatting preservation is not something to rely on. Pull, diff, push.forge init links to existing servers and sites; creating servers, sites, and certificates stays in the dashboard or the API. Scripts that assume otherwise will fail at step one.User mismatch look like CLI bugs but are usually ~/.ssh/config or key-loading problems. forge ssh:configure regenerates the alias if it drifts.How can I help you explore Laravel packages today?