# Laravel Cloud CLI
A Laravel Zero CLI for deploying and managing applications on [Laravel Cloud](https://cloud.laravel.com). Authenticate via OAuth, create and manage applications, environments, databases, caches, object storage, domains, and more—all from the terminal.
## Requirements
- **PHP 8.3+**
- **Composer**
- **Git** — for repository detection and `repo:config`
- **GitHub CLI (`gh`) or GitLab CLI (`glab`)** — optional, and only to create a repository from a directory that has no remote yet. Bitbucket has no CLI, so create the repository yourself and add it as a remote.
## Installation
Clone the repository and install dependencies:
```sh
gh repo clone laravel/cloud-cli
cd cloud-cli
composer install
```
## Setup Alias
To use the `cloud` command from anywhere, add an alias to your shell configuration:
**For Zsh (macOS default):**
```sh
echo 'alias cloud="php '$(pwd)'/cloud"' >> ~/.zshrc
source ~/.zshrc
```
**For Bash:**
```sh
echo 'alias cloud="php '$(pwd)'/cloud"' >> ~/.bashrc
source ~/.bashrc
```
Or manually add the alias to your `~/.zshrc` or `~/.bashrc` file:
```sh
alias cloud="php /path/to/cloud-cli/cloud"
```
## Authentication
Before using most commands, authenticate with Laravel Cloud:
```sh
cloud auth
```
This opens a browser for OAuth. API tokens are stored in `~/.config/cloud/config.json`. To manage those tokens interactively:
```sh
cloud auth:token
```
### CI and other non-interactive use
Browser OAuth needs a browser, so set the token in the environment instead. `LARAVEL_CLOUD_TOKEN` takes precedence over anything saved in `~/.config/cloud/config.json`, and nothing is written to disk:
```sh
export LARAVEL_CLOUD_TOKEN=your-api-token
cloud application:list -n
```
Create a token at https://cloud.laravel.com/docs/api/authentication#create-an-api-token.
An empty value counts as unset, so you can bypass it for a single command without unsetting it:
```sh
LARAVEL_CLOUD_TOKEN= cloud application:list -n
```
To save a token to the config file instead — on a machine you come back to, or when you need tokens for several organizations — pass it or pipe it:
```sh
cloud auth:token --add --token=your-api-token -n
echo "$YOUR_API_TOKEN" | cloud auth:token --add -n
```
Prefer the pipe where the process list is visible to others. `--remove` takes `--token=` the same way, and `--list` names the source of each token:
```sh
cloud auth:token --list -n
```
Listed tokens are masked down to their last four characters. Pass `--show-sensitive` to print them in full.
The token carries its own organization, so `--organization` becomes a check rather than a choice: when `LARAVEL_CLOUD_TOKEN` is set and you name an organization the token doesn't belong to, the command fails instead of using the wrong one.
## Repository configuration
Link the current Git repo to a Laravel Cloud application and set defaults (application, environment) so you don’t have to pass them every time:
```sh
cloud repo:config
```
Run this from your project root after `cloud auth`. Pass the application to skip the prompt, which is required when running non-interactively with more than one application:
```sh
cloud repo:config my-app -n
```
If you have tokens for more than one organization, name the one you want with `--organization` (its ID, name, or slug):
```sh
cloud repo:config my-app --organization=acme -n
```
## Quick start
1. **Ship** — Guided flow to create an application and deploy it:
```sh
cloud ship
```
2. **Deploy** — Deploy an existing application (uses repo config or prompts):
```sh
cloud deploy
```
Add `--push-env` to choose variables from your local `.env` to set on Cloud before deploying, or name them with `--push-env-keys=KEY_ONE,KEY_TWO`.
3. **Dashboard** — Open the app in the Laravel Cloud dashboard:
```sh
cloud dashboard
```
4. **Shell completions** — Enable tab completion:
```sh
cloud completions
```
## Commands reference
Many commands accept an optional resource ID/name and support `--json` for machine-readable output. When run interactively without arguments, the CLI will prompt for application, environment, or other context as needed.
### Auth & config
| Command | Description |
| ------------------- | ----------------------------------------------- |
| `cloud auth` | Authenticate with Laravel Cloud (browser OAuth) |
| `cloud auth:token` | Manage API tokens |
| `cloud repo:config` | Configure defaults for the current repository |
### Applications
| Command | Description |
| --------------------------------- | ------------------------------ |
| `cloud application:list` | List applications |
| `cloud application:get` | Get application details |
| `cloud application:create` | Create an application |
| `cloud application:update` | Update an application |
| `cloud application:delete` | Delete an application |
| `cloud application:delete-avatar` | Remove an application's avatar |
### Environments
| Command | Description |
| ------------------------------------ | ------------------------------------------------------------ |
| `cloud environment:list` | List environments |
| `cloud environment:get` | Get environment details |
| `cloud environment:create` | Create an environment |
| `cloud environment:update` | Update an environment |
| `cloud environment:delete` | Delete an environment |
| `cloud environment:variables` | Manage environment variables (append, set, or delete) |
| `cloud environment:logs` | View environment logs |
| `cloud environment:metrics` | View environment compute and HTTP metrics |
| `cloud environment:purge-edge-cache` | Purge the edge cache (everything, or a path, prefix, or tag) |
| `cloud environment:vanity-domain` | Change the environment's Laravel Cloud domain |
`environment:purge-edge-cache` purges everything cached at the edge for the environment unless you pass one of `--path`, `--prefix`, or `--tag`. Paths and prefixes start with `/`; purging by tag needs a dedicated edge network. Cloud queues the purge, and repeating the same purge right away has no effect.
`environment:vanity-domain` takes only the first part of the domain: `--name=my-app` gives `my-app.laravel.cloud`. The new domain takes effect on the next deploy, and the domain can be changed only once every 30 minutes, so the command asks for confirmation (or `--force`). Afterward it offers to deploy the environment; pass `--deploy` to do that without asking.
### Secrets
Secrets are organization-wide encrypted values that can be attached to environments. Values are encrypted locally with the organization's public key before they are sent, so plaintext never leaves your machine.
| Command | Description |
| --------------------------------- | --------------------------------------- |
| `cloud secret:list` | List secrets |
| `cloud secret:create` | Create a secret |
| `cloud secret:update` | Update a secret |
| `cloud secret:delete` | Delete a secret |
| `cloud environment-secret:list` | List secrets attached to an environment |
| `cloud environment-secret:attach` | Attach secrets to an environment |
| `cloud environment-secret:detach` | Detach secrets from an environment |
`secret:create` and `secret:update` encrypt with `ext-sodium`, which ships with PHP but is a separate package on some distributions. No other command needs it.
`secret:create` and `secret:update` read the value from STDIN when `--value` is not given, which keeps it out of your shell history and out of the process list:
```sh
op read "op://vault/stripe/api-key" | cloud secret:create --name=STRIPE_KEY -n
```
### Deploy & ship
| Command | Description |
| ----------------------- | ---------------------------------------------- |
| `cloud ship` | Ship the application to Laravel Cloud (guided) |
| `cloud deploy` | Deploy to Laravel Cloud |
| `cloud deploy:monitor` | Monitor deployments |
| `cloud deployment:list` | List deployments |
| `cloud deployment:get` | Get deployment details |
| `cloud deployment:logs` | View a deployment's build and deploy logs |
`deployment:logs` shows each build and deploy step with its status, duration, and output, so a failed deploy shows the step that broke and why. Logs are kept for a year.
### Instances
| Command | Description |
| ----------------------- | ----------------------------- |
| `cloud instance:list` | List instances |
| `cloud instance:get` | Get instance details |
| `cloud instance:create` | Create an instance |
| `cloud instance:update` | Update an instance |
| `cloud instance:delete` | Delete an instance |
| `cloud instance:sizes` | List available instance sizes |
### Databases
| Command | Description |
| -------------------------------- | -------------------------------------- |
| `cloud database-cluster:list` | List database clusters |
| `cloud database-cluster:get` | Get cluster details |
| `cloud database-cluster:create` | Create a database cluster |
| `cloud database-cluster:update` | Update a database cluster |
| `cloud database-cluster:delete` | Delete a database cluster |
| `cloud database-cluster:metrics` | View cluster metrics |
| `cloud database-cluster:types` | List database types and versions |
| `cloud database:list` | List databases (schemas) in a cluster |
| `cloud database:get` | Get database details |
| `cloud database:create` | Create a database |
| `cloud database:delete` | Delete a database |
| `cloud database:open` | Open database locally |
| `cloud database-snapshot:list` | List snapshots |
| `cloud database-snapshot:get` | Get snapshot details |
| `cloud database-snapshot:create` | Create a snapshot |
| `cloud database-snapshot:delete` | Delete a snapshot |
| `cloud database-restore:create` | Create a restore from snapshot or PITR |
### Cache
| Command | Description |
| --------------------- | -------------------------- |
| `cloud cache:list` | List caches |
| `cloud cache:get` | Get cache details |
| `cloud cache:create` | Create a cache |
| `cloud cache:update` | Update a cache |
| `cloud cache:delete` | Delete a cache |
| `cloud cache:types` | List available cache types |
| `cloud cache:metrics` | View cache metrics |
### Object storage (buckets)
| Command | Description |
| ------------------------- | ---------------------- |
| `cloud bucket:list` | List buckets |
| `cloud bucket:get` | Get bucket details |
| `cloud bucket:create` | Create a bucket |
| `cloud bucket:update` | Update a bucket |
| `cloud bucket:delete` | Delete a bucket |
| `cloud bucket-key:list` | List bucket keys |
| `cloud bucket-key:get` | Get bucket key details |
| `cloud bucket-key:create` | Create a bucket key |
| `cloud bucket-key:update` | Update a bucket key |
| `cloud bucket-key:delete` | Delete a bucket key |
### Domains
| Command | Description |
| --------------------- | ------------------ |
| `cloud domain:list` | List domains |
| `cloud domain:get` | Get domain details |
| `cloud domain:create` | Create a domain |
| `cloud domain:update` | Update a domain |
| `cloud domain:delete` | Delete a domain |
| `cloud domain:verify` | Verify domain DNS |
### Email (Resend)
| Command | Description |
| ---------------------- | ---------------------------------------------------- |
| `cloud resend:domains` | List Resend sending domains |
| `cloud resend:attach` | Attach Resend to an environment so it can send email |
| `cloud resend:update` | Change the sender address or name for an environment |
| `cloud resend:detach` | Detach Resend from an environment |
| `cloud resend:keys` | List the sending keys an environment can reuse |
Connect your Resend account and verify a sending domain in the dashboard first, under your organization's integration settings; the API can't do either. The sender address must use a verified domain.
`resend:attach` creates a new sending key, or reuses another environment's with `--reuse-key-id` (find IDs with `resend:keys`). Cloud then sets `RESEND_API_KEY`, `MAIL_MAILER`, `MAIL_FROM_ADDRESS`, and `MAIL_FROM_NAME`, and removes any copies of them from the environment's own variables. Laravel needs the `resend/resend-php` package to send through Resend; when the current directory is a Composer project without it, `resend:attach` offers to install it.
Without an environment argument, `resend:attach` offers only environments without Resend, and `resend:update` and `resend:detach` only those with it. `resend:detach` deletes the sending key unless another environment uses it, and needs `--force` when run non-interactively.
### WebSockets
| Command | Description |
| ------------------------------------- | ------------------------------ |
| `cloud websocket-cluster:list` | List WebSocket clusters |
| `cloud websocket-cluster:get` | Get cluster details |
| `cloud websocket-cluster:create` | Create a WebSocket cluster |
| `cloud websocket-cluster:update` | Update a WebSocket cluster |
| `cloud websocket-cluster:delete` | Delete a WebSocket cluster |
| `cloud websocket-cluster:metrics` | View cluster metrics |
| `cloud websocket-cluster:types` | List cluster types and tiers |
| `cloud websocket-application:list` | List WebSocket applications |
| `cloud websocket-application:get` | Get application details |
| `cloud websocket-application:create` | Create a WebSocket application |
| `cloud websocket-application:update` | Update a WebSocket application |
| `cloud websocket-application:delete` | Delete a WebSocket application |
| `cloud websocket-application:metrics` | View application metrics |
### Background processes
| Command | Description |
| --------------------------------- | --------------------------- |
| `cloud background-process:list` | List background processes |
| `cloud background-process:get` | Get process details |
| `cloud background-process:create` | Create a background process |
| `cloud background-process:update` | Update a background process |
| `cloud background-process:delete` | Delete a background process |
### Scheduled commands
| Command | Description |
| -------------------------------- | --------------------------------------- |
| `cloud scheduled-command:list` | List scheduled commands for an instance |
| `cloud scheduled-command:get` | Get scheduled command details |
| `cloud scheduled-command:create` | Create a scheduled command |
| `cloud scheduled-command:update` | Update a scheduled command |
| `cloud scheduled-command:delete` | Delete a scheduled command |
Schedules are five-field cron expressions evaluated in UTC, such as `0 0 * * *`. The `@hourly`, `@daily`, `@midnight`, `@weekly`, `@monthly`, `@yearly`, and `@annually` descriptors also work.
### Commands (one-off)
| Command | Description |
| -------------------- | -------------------------------- |
| `cloud command:list` | List commands for an environment |
| `cloud command:get` | Get command details |
| `cloud command:run` | Run a command on an environment |
### Managed queues
Managed queues are a special kind of instance. Pass the instance ID directly or let the CLI prompt for one.
| Command | Description |
| --------------------------------------- | ---------------------------------------- |
| `cloud managed-queue:create` | Create a managed queue in an environment |
| `cloud managed-queue:pause` | Pause a managed queue |
| `cloud managed-queue:resume` | Resume a managed queue |
| `cloud managed-queue:purge` | Purge all messages from a managed queue |
| `cloud managed-queue:set-default` | Set a managed queue as the default |
| `cloud managed-queue:failed-jobs` | List failed jobs for a managed queue |
| `cloud managed-queue:retry-failed-job` | Retry a failed job on a managed queue |
| `cloud managed-queue:delete-failed-job` | Delete failed jobs from a managed queue |
`managed-queue:create` accepts `--name`, `--size`, `--max-workers`, `--visibility-timeout`, `--polling-interval` and `--shutdown-timeout` so it can run non-interactively. `pause`, `purge` and `delete-failed-job` accept `--force` to skip the confirmation prompt. `delete-failed-job` takes one or more job IDs, or `--failed-before` to delete every job that failed before a date.
### Usage
| Command | Description |
| -------------------------------- | ------------------------------------------------------------ |
| `cloud usage` | View billing summary for the current period |
| `cloud usage --detailed` | Full breakdown with per-app, per-resource, and add-on tables |
| `cloud usage --period=previous` | View a previous billing period (current, previous, 1, 2, 3) |
| `cloud usage --environment=<id>` | Filter usage by environment |
### Other
| Command | Description |
| ------------------------------ | ---------------------------------------- |
| `cloud dashboard` | Open app in Cloud dashboard |
| `cloud browser` | Open the application in the browser |
| `cloud ip:addresses` | Get Laravel Cloud IP addresses by region |
| `cloud dedicated-cluster:list` | List dedicated clusters |
| `cloud edge-network:list` | List edge networks |
| `cloud tinker` | Tinker in your Laravel Cloud environment |
| `cloud skills:install` | Install Laravel Cloud CLI agent skills |
| `cloud completions` | Generate and install shell completions |
`cloud tinker` runs code against an environment, either interactively or via `--code=` for scripting (`--timeout=` caps how long to wait for output, default 60s). `cloud skills:install` installs the CLI's agent skills for supported coding agents; use `--global` or `--project` to choose the location and `--agent=` (repeatable) to pick specific agents.
## Configuration
- **User config:** `~/.config/cloud/config.json` (auth tokens and preferences).
- **Repo defaults:** After `cloud repo:config`, the current Git repo stores which application and environment to use so you can run `cloud deploy` and similar without selecting every time.
## Development
- **Code style:** Laravel/PSR-12. Format with [Laravel Pint](https://laravel.com/docs/pint):
```sh
./vendor/bin/pint --dirty
```
- **Tests:** [Pest](https://pestphp.com/):
```sh
./vendor/bin/pest
```
- **Static analysis:** [PHPStan](https://phpstan.org/):
```sh
./vendor/bin/phpstan analyse
```
## Links
- [Laravel Cloud](https://cloud.laravel.com)
- [Laravel Cloud API docs](https://cloud.laravel.com/docs/api/introduction)
- [Laravel Zero](https://laravel-zero.com)