# Report Abuse Source: https://cloud.laravel.com/docs/abuse Report abuse and violations of Laravel Cloud terms of service and policies. Please email us at [security@laravel.com](mailto:security@laravel.com) ## Our commitment Your security and safety are our top priorities. All abuse reports are handled with your confidentiality and security guaranteed. All abuse reports are handled sensitively and we follow best practices for disclosing issues responsibly. Laravel adheres to a zero tolerance policy when it comes to abuse and we take immediate action to ensure the security of our platform. # Create application Source: https://cloud.laravel.com/docs/api/applications/create-application https://cloud.laravel.com/api-docs/api.json post /applications Create a new application. # Delete application Source: https://cloud.laravel.com/docs/api/applications/delete-application https://cloud.laravel.com/api-docs/api.json delete /applications/{application} Delete an application and all of its environments. # Delete application avatar Source: https://cloud.laravel.com/docs/api/applications/delete-application-avatar https://cloud.laravel.com/api-docs/api.json delete /applications/{application}/avatar Remove the avatar from an application. # Get application Source: https://cloud.laravel.com/docs/api/applications/get-application https://cloud.laravel.com/api-docs/api.json get /applications/{application} Get a specific application. # List applications Source: https://cloud.laravel.com/docs/api/applications/list-applications https://cloud.laravel.com/api-docs/api.json get /applications Get a list of all applications for the authenticated organization. # Update application Source: https://cloud.laravel.com/docs/api/applications/update-application https://cloud.laravel.com/api-docs/api.json patch /applications/{application} Update an application. # Upload application avatar Source: https://cloud.laravel.com/docs/api/applications/upload-application-avatar https://cloud.laravel.com/api-docs/api.json post /applications/{application}/avatar Upload or replace the avatar for an application. # API authentication for Laravel Cloud Source: https://cloud.laravel.com/docs/api/authentication Authenticate and access the Laravel Cloud API using tokens and credentials. The Laravel Cloud API uses token-based authentication. You can generate an API token from your Laravel Cloud organization settings. Once you have your token, include it in the `Authorization` header of your API requests as follows: ```http theme={null} Authorization: Bearer YOUR_API_TOKEN ``` ### Managing API tokens You can manage your API tokens from your Laravel Cloud organization settings. Navigate to the API tokens section to create, view, and revoke your tokens. API Tokens management interface in Laravel Cloud settings #### Create an API token To create a new API token, follow these steps: 1. Navigate to your Laravel Cloud organization settings 2. Click on the "API tokens" section in the sidebar 3. Click the "Create API Token" button 4. Enter a descriptive name for your token to help you identify its purpose 5. Select an expiration period for the token 6. Click "Create" to generate your new API token Make sure to copy your API token immediately after creation, as it will only be displayed once for security reasons. Store it securely and never share it publicly. #### Revoke an API token To revoke an API token that you no longer need or that may have been compromised, follow these steps: 1. Navigate to your Laravel Cloud organization settings 2. Click on the "API tokens" section in the sidebar 3. Find the API token you want to revoke in the list 4. Click the "Revoke" button next to the token 5. Confirm your password when prompted 6. Click "Revoke API token" to permanently delete the token Once an API token is revoked, it cannot be restored. Any applications using this token will immediately lose access to the API. Make sure to update your applications with a new token before revoking the old one if you need continued access. #### API token expiration API tokens have configurable expiration periods to help maintain security. When creating a new token, you can choose from the following expiration options: * **1 month:** recommended for short-term projects or testing * **6 months:** a good balance between security and convenience * **1 year:** suitable for long-term integrations Once a token expires, it will no longer be valid for API requests and you'll need to generate a new one. Make sure to update your applications with the new token before the old one expires. ### Scoping API tokens By default, an API token has full access to your organization and can interact with every endpoint, application, and environment. To follow the principle of least privilege, you can scope a token down so it only has the access it needs. Scoping is optional, and you configure it when you create a token. Laravel Cloud provides two independent controls for scoping a token: * **Permissions** limit which API endpoints the token can access. * **Resource scoping** limits which applications and environments the token can interact with. You can apply either control on its own or combine them. A token's scope is separate from user roles and permissions. A token does not inherit or mirror the access of the user who created it, so you must define its scope explicitly. #### Permissions Permissions determine which API endpoints a token can call. When you assign permissions, the token can perform only the actions you select, and Cloud rejects requests to any other endpoint. For example, you might grant a token permission to view deployments and trigger new ones while withholding the ability to manage environment variables or delete resources. This lets you issue a token for a continuous integration pipeline that can deploy your application without exposing your secrets. #### Resource scoping Resource scoping determines which applications and environments a token can interact with. When you scope a token to specific resources, Cloud rejects requests to any application or environment outside that scope. Resource scoping and permissions work together. For example, you can create a token that has permission to trigger deployments and is scoped to only your staging environment, so the token can deploy to staging but never to production. Create a separate, tightly scoped token for each integration or automation rather than reusing one broadly scoped token. If a token is ever compromised, it can reach only the endpoints and resources you granted, and you can revoke it without disrupting your other integrations. # Create background process Source: https://cloud.laravel.com/docs/api/background-processes/create-background-process https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/background-processes Create a new background process for an instance. # Delete background process Source: https://cloud.laravel.com/docs/api/background-processes/delete-background-process https://cloud.laravel.com/api-docs/api.json delete /background-processes/{backgroundProcess} Delete a background process. # Get background process Source: https://cloud.laravel.com/docs/api/background-processes/get-background-process https://cloud.laravel.com/api-docs/api.json get /background-processes/{backgroundProcess} Get the details of a specific background process. # List background processes Source: https://cloud.laravel.com/docs/api/background-processes/list-background-processes https://cloud.laravel.com/api-docs/api.json get /instances/{instance}/background-processes Get a list of all background processes for the given instance. # Update background process Source: https://cloud.laravel.com/docs/api/background-processes/update-background-process https://cloud.laravel.com/api-docs/api.json patch /background-processes/{backgroundProcess} Update a background process. # Create object storage key Source: https://cloud.laravel.com/docs/api/bucket-keys/create-object-storage-key https://cloud.laravel.com/api-docs/api.json post /buckets/{filesystem}/keys Create a new key for an object storage bucket. # Delete object storage key Source: https://cloud.laravel.com/docs/api/bucket-keys/delete-object-storage-key https://cloud.laravel.com/api-docs/api.json delete /bucket-keys/{filesystemKey} Delete an object storage key. # Get object storage key Source: https://cloud.laravel.com/docs/api/bucket-keys/get-object-storage-key https://cloud.laravel.com/api-docs/api.json get /bucket-keys/{filesystemKey} Get a specific object storage key. # List object storage keys Source: https://cloud.laravel.com/docs/api/bucket-keys/list-object-storage-keys https://cloud.laravel.com/api-docs/api.json get /buckets/{filesystem}/keys Get a list of all keys for a specific object storage bucket. # Update object storage key Source: https://cloud.laravel.com/docs/api/bucket-keys/update-object-storage-key https://cloud.laravel.com/api-docs/api.json patch /bucket-keys/{filesystemKey} Update an object storage key. # Create cache Source: https://cloud.laravel.com/docs/api/caches/create-cache https://cloud.laravel.com/api-docs/api.json post /caches Create a new cache. # Delete cache Source: https://cloud.laravel.com/docs/api/caches/delete-cache https://cloud.laravel.com/api-docs/api.json delete /caches/{cache} Delete a cache. # Get cache Source: https://cloud.laravel.com/docs/api/caches/get-cache https://cloud.laravel.com/api-docs/api.json get /caches/{cache} Get a specific cache. # Get cache metrics Source: https://cloud.laravel.com/docs/api/caches/get-cache-metrics https://cloud.laravel.com/api-docs/api.json get /caches/{cache}/metrics Get metrics for a specific cache. `size.total` is the latest size. `bandwidth_usage.total` is the bandwidth used so far this calendar month, whatever the period. # List all available cache types with their configuration options Source: https://cloud.laravel.com/docs/api/caches/list-all-available-cache-types-with-their-configuration-options https://cloud.laravel.com/api-docs/api.json get /caches/types Get a list of all cache types available when creating a cache, including the regions and sizes each type supports. # List caches Source: https://cloud.laravel.com/docs/api/caches/list-caches https://cloud.laravel.com/api-docs/api.json get /caches Get a list of all caches for the authenticated organization. # Update cache Source: https://cloud.laravel.com/docs/api/caches/update-cache https://cloud.laravel.com/api-docs/api.json patch /caches/{cache} Update a cache. # Laravel Cloud CLI Source: https://cloud.laravel.com/docs/api/cli Deploy and manage your Laravel Cloud applications from the command line. The Laravel Cloud CLI lets you deploy and manage your Laravel Cloud applications, environments, and resources from your terminal or a CI/CD pipeline. ## Requirements * PHP 8.2 or higher * Composer * Git The [GitHub CLI](https://cli.github.com/) (`gh`) is optional but recommended. It is used by the `ship` command to create a GitHub repository if your project doesn't already have one. ## Installation Install the CLI globally: ```bash theme={null} composer global require laravel/cloud-cli ``` *Note:* Make sure your global vendor binaries directory is in your `$PATH` environment variable, you can read more about this in the [Composer documentation](https://getcomposer.org/doc/03-cli.md#global). ### Shell completions The CLI supports tab completions for Bash, Zsh, and Fish. To generate and install completions for your shell, run: ```bash theme={null} cloud completions ``` You can also target a specific shell directly: ```bash theme={null} cloud completions zsh cloud completions bash cloud completions fish ``` ## Authentication Before using the CLI, you need to authenticate with your Laravel Cloud account. The CLI supports two authentication methods: browser-based OAuth and manual token entry. ### Browser authentication The simplest way to authenticate is through your browser: ```bash theme={null} cloud auth ``` This command opens your default browser, prompts you to authorize the CLI, and stores the resulting API token locally. The token is saved in `~/.config/cloud/config.json`. ### Token authentication You can also manage API tokens directly. This is useful for CI/CD environments or when you prefer to provide tokens manually: ```bash theme={null} # Add a token cloud auth:token --add # List stored tokens cloud auth:token --list # Remove a token cloud auth:token --remove ``` If you have tokens for multiple organizations, the CLI will prompt you to select which organization to use when running commands. ## Quick start The fastest way to get an application running on Laravel Cloud is the `ship` command. From inside your project directory, run: ```bash theme={null} cloud ship ``` This guided flow walks you through creating an application, configuring your environment, and deploying — all in a single command. It detects your repository, prompts for a region and application name, and optionally syncs your `.env` variables, creates databases or caches, and configures features like the scheduler, Octane, or WebSockets. ## Deploying To deploy your application, run the `deploy` command from your project directory: ```bash theme={null} cloud deploy ``` The CLI resolves the target application and environment automatically using your repository configuration. After the deployment starts, the CLI monitors its progress and reports the result in real time. To open your application in the browser after a successful deployment: ```bash theme={null} cloud deploy --open ``` You can also monitor an active deployment separately: ```bash theme={null} cloud deploy:monitor ``` ## Repository configuration To avoid specifying your application and environment on every command, you can save defaults for your repository: ```bash theme={null} cloud repo:config ``` This creates a `.cloud/config.json` file in your project root that stores the `application_id` and `organization_id`. Subsequent commands will use these defaults automatically. ## Managing resources The CLI provides full CRUD operations for Laravel Cloud resources. Command examples below show the most common operations. ### Applications ```bash theme={null} cloud application:list cloud application:get cloud application:create cloud application:update ``` ### Environments ```bash theme={null} cloud environment:list cloud environment:get cloud environment:create cloud environment:update cloud environment:delete ``` To update environment variables interactively or by using command options: ```bash theme={null} cloud environment:variables ``` To view environment logs: ```bash theme={null} cloud environment:logs ``` ### Instances ```bash theme={null} cloud instance:list cloud instance:get cloud instance:create cloud instance:update cloud instance:delete cloud instance:sizes ``` ### Databases ```bash theme={null} cloud database-cluster:list cloud database-cluster:get cloud database-cluster:create cloud database-cluster:update cloud database-cluster:delete ``` You can manage individual databases within a cluster: ```bash theme={null} cloud database:list cloud database:get cloud database:create cloud database:delete ``` To connect to a database locally: ```bash theme={null} cloud database:open ``` Database snapshots and restores are also available: ```bash theme={null} cloud database-snapshot:list cloud database-snapshot:get cloud database-snapshot:create cloud database-snapshot:delete cloud database-restore:create ``` ### Caches ```bash theme={null} cloud cache:list cloud cache:create cloud cache:update cloud cache:delete cloud cache:types ``` ### Object storage ```bash theme={null} cloud bucket:list cloud bucket:get cloud bucket:create cloud bucket:update cloud bucket:delete ``` Bucket keys can be managed separately: ```bash theme={null} cloud bucket-key:list cloud bucket-key:get cloud bucket-key:create cloud bucket-key:update cloud bucket-key:delete ``` ### Domains ```bash theme={null} cloud domain:list cloud domain:create cloud domain:update cloud domain:delete cloud domain:verify ``` ### WebSockets ```bash theme={null} cloud websocket-cluster:list cloud websocket-cluster:get cloud websocket-cluster:create cloud websocket-cluster:update cloud websocket-cluster:delete ``` WebSocket applications within a cluster: ```bash theme={null} cloud websocket-application:list cloud websocket-application:get cloud websocket-application:create cloud websocket-application:update cloud websocket-application:delete ``` ### Background processes ```bash theme={null} cloud background-process:list cloud background-process:get cloud background-process:create cloud background-process:update cloud background-process:delete ``` ### Commands To run a one-off command on an environment: ```bash theme={null} cloud command:run ``` To list previously executed commands: ```bash theme={null} cloud command:list cloud command:get ``` ### Tinker The `tinker` command opens an interactive PHP REPL connected to your Laravel Cloud environment, allowing you to execute PHP code directly against your running application: ```bash theme={null} cloud tinker ``` By default, a multi-line text input is presented in your terminal where you can type and submit PHP code. Each submission is sent to your Cloud environment for execution, and the result is displayed in your terminal. The session remains open so you can continue executing code. #### Editor mode If you prefer to write code in your editor, use the `--editor` option: ```bash theme={null} cloud tinker --editor=code ``` This opens a temporary file in your editor. Every time you save the file, the code is automatically sent to your Cloud environment for execution and the result is displayed in your terminal. The session ends when you close the file. Common editor values include `code`, `subl`, `vim`, and `phpstorm`. If no value is given, the `VISUAL` or `EDITOR` environment variable is used. #### Non-interactive mode To execute a single snippet of PHP code without entering the interactive session, use the `--code` option: ```bash theme={null} cloud tinker --code="echo App\Models\User::count();" ``` This is useful for scripting and CI/CD pipelines. #### Timeout By default, code execution will time out after 60 seconds. You can adjust this with the `--timeout` option: ```bash theme={null} cloud tinker --timeout=120 ``` ## Utility commands Open your application in the Laravel Cloud dashboard: ```bash theme={null} cloud dashboard ``` Open your application in the browser: ```bash theme={null} cloud browser ``` Retrieve Laravel Cloud IP addresses by region: ```bash theme={null} cloud ip:addresses ``` ## Agent skills The CLI can install Laravel Cloud skills for your AI coding agents. Skills are fetched from the `laravel/agent-skills` repository and installed into the appropriate directory for each agent. ```bash theme={null} cloud skills:install ``` The command auto-detects which agents you have configured and prompts you to select which ones to install skills for. Supported agents include Claude, Cursor, Junie, GitHub Copilot, and a generic agent format. ### Global vs. project installation By default, skills are installed globally if you are outside a Laravel Cloud project, or to the current project if the Cloud CLI is detected as a local dependency. You can override this behavior: ```bash theme={null} # Install globally (e.g. ~/.claude/skills) cloud skills:install --global # Install to the current project (e.g. .claude/skills) cloud skills:install --project ``` ### Specifying agents To install skills for specific agents without being prompted: ```bash theme={null} cloud skills:install --agent=claude --agent=cursor ``` ### Overwriting existing skills If skills have already been installed, use the `--force` flag to overwrite them: ```bash theme={null} cloud skills:install --force ``` ## JSON output Many commands support a `--json` flag for machine-readable output, which is useful for automation and CI/CD pipelines: ```bash theme={null} cloud instance:list --json cloud environment:variables --json --action=set --key=APP_ENV --value=production ``` In non-interactive environments (such as GitHub Actions), interactive prompts are disabled automatically. # Get command Source: https://cloud.laravel.com/docs/api/commands/get-command https://cloud.laravel.com/api-docs/api.json get /commands/{command} Get the details of a specific command. # List commands Source: https://cloud.laravel.com/docs/api/commands/list-commands https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/commands Get a list of all commands for the given environment. # Run command Source: https://cloud.laravel.com/docs/api/commands/run-command https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/commands Run a command on the given environment. # Create database cluster Source: https://cloud.laravel.com/docs/api/database-clusters/create-database-cluster https://cloud.laravel.com/api-docs/api.json post /databases/clusters Create a new database cluster. Unless `create_default_database` is `false`, a default database will also be created and returned on the `databases` relationship. # Delete database cluster Source: https://cloud.laravel.com/docs/api/database-clusters/delete-database-cluster https://cloud.laravel.com/api-docs/api.json delete /databases/clusters/{database} Delete a database cluster. # Get database cluster Source: https://cloud.laravel.com/docs/api/database-clusters/get-database-cluster https://cloud.laravel.com/api-docs/api.json get /databases/clusters/{database} Get a specific database cluster. # Get database cluster metrics Source: https://cloud.laravel.com/docs/api/database-clusters/get-database-cluster-metrics https://cloud.laravel.com/api-docs/api.json get /databases/clusters/{database}/metrics Get metrics for a specific database cluster. `replica_lag` is always empty on this endpoint. # List database clusters Source: https://cloud.laravel.com/docs/api/database-clusters/list-database-clusters https://cloud.laravel.com/api-docs/api.json get /databases/clusters Get a list of all database clusters for the authenticated organization. # List database types Source: https://cloud.laravel.com/docs/api/database-clusters/list-database-types https://cloud.laravel.com/api-docs/api.json get /databases/types List all available database types with their configuration schemas. Each type lists the versions a database may be created with; pass one of them as `version` when creating a database. The retired types that baked the version into the type are listed after them with no versions and remain accepted when creating a database, for backwards compatibility. # Update database cluster Source: https://cloud.laravel.com/docs/api/database-clusters/update-database-cluster https://cloud.laravel.com/api-docs/api.json patch /databases/clusters/{database} Update a database cluster. # Create a database restore Source: https://cloud.laravel.com/docs/api/database-restores/create-a-database-restore https://cloud.laravel.com/api-docs/api.json post /databases/clusters/{database}/restore Restore a database cluster from a point in time or snapshot. Returns the newly created database. # Create a database snapshot Source: https://cloud.laravel.com/docs/api/database-snapshots/create-a-database-snapshot https://cloud.laravel.com/api-docs/api.json post /databases/clusters/{database}/snapshots Create a new manual snapshot for a database cluster. # Delete a database snapshot Source: https://cloud.laravel.com/docs/api/database-snapshots/delete-a-database-snapshot https://cloud.laravel.com/api-docs/api.json delete /database-snapshots/{databaseSnapshot} Delete a snapshot from a database cluster. Automatic backups cannot be deleted while point-in-time recovery is enabled. # Get a database snapshot Source: https://cloud.laravel.com/docs/api/database-snapshots/get-a-database-snapshot https://cloud.laravel.com/api-docs/api.json get /database-snapshots/{databaseSnapshot} Get a specific database snapshot. # List database snapshots Source: https://cloud.laravel.com/docs/api/database-snapshots/list-database-snapshots https://cloud.laravel.com/api-docs/api.json get /databases/clusters/{database}/snapshots Get a list of all snapshots for a specific database cluster. # Create database Source: https://cloud.laravel.com/docs/api/databases-legacy/create-database https://cloud.laravel.com/api-docs/api.json post /databases Use POST /databases/clusters instead. # Delete database Source: https://cloud.laravel.com/docs/api/databases-legacy/delete-database https://cloud.laravel.com/api-docs/api.json delete /databases/{database} Use DELETE /databases/clusters/{database} instead. # Get database Source: https://cloud.laravel.com/docs/api/databases-legacy/get-database https://cloud.laravel.com/api-docs/api.json get /databases/{database} Use GET /databases/clusters/{database} instead. # List databases Source: https://cloud.laravel.com/docs/api/databases-legacy/list-databases https://cloud.laravel.com/api-docs/api.json get /databases Use GET /databases/clusters instead. # Update database Source: https://cloud.laravel.com/docs/api/databases-legacy/update-database https://cloud.laravel.com/api-docs/api.json patch /databases/{database} Use PATCH /databases/clusters/{database} instead. # Create a database Source: https://cloud.laravel.com/docs/api/databases/create-a-database https://cloud.laravel.com/api-docs/api.json post /databases/clusters/{database}/databases Create a new database in a database cluster. # Delete a database Source: https://cloud.laravel.com/docs/api/databases/delete-a-database https://cloud.laravel.com/api-docs/api.json delete /databases/clusters/{database}/databases/{schema} Delete a database from a database cluster. # Get a database Source: https://cloud.laravel.com/docs/api/databases/get-a-database https://cloud.laravel.com/api-docs/api.json get /databases/clusters/{database}/databases/{schema} Get a specific database. # List databases Source: https://cloud.laravel.com/docs/api/databases/list-databases https://cloud.laravel.com/api-docs/api.json get /databases/clusters/{database}/databases Get a list of all databases for a specific database cluster. # List dedicated clusters Source: https://cloud.laravel.com/docs/api/dedicated-clusters/list-dedicated-clusters https://cloud.laravel.com/api-docs/api.json get /dedicated-clusters Get a list of all dedicated clusters for the authenticated organization. # Get deployment Source: https://cloud.laravel.com/docs/api/deployments/get-deployment https://cloud.laravel.com/api-docs/api.json get /deployments/{deployment} Get the details of a specific deployment. # Get deployment logs Source: https://cloud.laravel.com/docs/api/deployments/get-deployment-logs https://cloud.laravel.com/api-docs/api.json get /deployments/{deployment}/logs Get the build and deploy logs for a specific deployment. # Initiate deployment Source: https://cloud.laravel.com/docs/api/deployments/initiate-deployment https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/deployments Initiate a deployment for the given environment. # List deployments Source: https://cloud.laravel.com/docs/api/deployments/list-deployments https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/deployments Get a list of all deployments for the given environment. # Create domain Source: https://cloud.laravel.com/docs/api/domains/create-domain https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/domains Create a new domain for the given environment. After creating the domain, you'll have to add the required DNS records to your DNS provider. This might be a 2-step process, depending on the verification method used. You can check the required DNS records in the response of this endpoint, and you can verify the domain using the "verify" query parameter in the "Get domain" endpoint. # Delete domain Source: https://cloud.laravel.com/docs/api/domains/delete-domain https://cloud.laravel.com/api-docs/api.json delete /domains/{domain} Delete a specific domain. # Get domain Source: https://cloud.laravel.com/docs/api/domains/get-domain https://cloud.laravel.com/api-docs/api.json get /domains/{domain} Show a specific domain. # List domains Source: https://cloud.laravel.com/docs/api/domains/list-domains https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/domains List all domains for the given environment. # Update domain Source: https://cloud.laravel.com/docs/api/domains/update-domain https://cloud.laravel.com/api-docs/api.json patch /domains/{domain} Update a specific domain. # Verify a domain Source: https://cloud.laravel.com/docs/api/domains/verify-a-domain https://cloud.laravel.com/api-docs/api.json post /domains/{domain}/verify Checks whether the DNS records for a given domain have been properly set up. # List edge networks Source: https://cloud.laravel.com/docs/api/edge-networks/list-edge-networks https://cloud.laravel.com/api-docs/api.json get /edge-networks Get a list of the edge networks available to the authenticated organization, including the shared edge network. # Attach Resend to environment Source: https://cloud.laravel.com/docs/api/email/attach-resend-to-environment https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/resend Attach Resend to an environment, creating a new sending key or reusing an existing one. # Detach Resend from environment Source: https://cloud.laravel.com/docs/api/email/detach-resend-from-environment https://cloud.laravel.com/api-docs/api.json delete /environments/{environment}/resend Detach Resend from an environment, deleting its sending key unless it is shared. # List reusable sending keys Source: https://cloud.laravel.com/docs/api/email/list-reusable-sending-keys https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/resend/keys List the Resend sending keys from other environments that can be reused by an environment. # List sending domains Source: https://cloud.laravel.com/docs/api/email/list-sending-domains https://cloud.laravel.com/api-docs/api.json get /resend/domains Get a list of all Resend sending domains for the authenticated organization. # Update environment Resend sender Source: https://cloud.laravel.com/docs/api/email/update-environment-resend-sender https://cloud.laravel.com/api-docs/api.json patch /environments/{environment}/resend Update the sender address and name of an environment's Resend integration. # Add environment variables Source: https://cloud.laravel.com/docs/api/environments/add-environment-variables https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/variables Add environment variables to an environment. # Attach secrets to environment Source: https://cloud.laravel.com/docs/api/environments/attach-secrets-to-environment https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/secrets Attach one or more of the organization's secrets to an environment. Secrets that are already attached to the environment are ignored. # Create environment Source: https://cloud.laravel.com/docs/api/environments/create-environment https://cloud.laravel.com/api-docs/api.json post /applications/{application}/environments Create a new environment. # Delete environment Source: https://cloud.laravel.com/docs/api/environments/delete-environment https://cloud.laravel.com/api-docs/api.json delete /environments/{environment} Delete an environment. # Delete environment variables Source: https://cloud.laravel.com/docs/api/environments/delete-environment-variables https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/variables/delete Remove specific environment variables by key name. This operation is atomic: if any of the specified keys do not exist, no variables will be deleted and an error will be returned indicating which keys were missing. # Detach secret from environment Source: https://cloud.laravel.com/docs/api/environments/detach-secret-from-environment https://cloud.laravel.com/api-docs/api.json delete /environments/{environment}/secrets/{secret} Detach one of the organization's secrets from an environment. The secret itself is not deleted. # Get environment Source: https://cloud.laravel.com/docs/api/environments/get-environment https://cloud.laravel.com/api-docs/api.json get /environments/{environment} Get a specific environment. # Get environment metrics Source: https://cloud.laravel.com/docs/api/environments/get-environment-metrics https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/metrics Get metrics for a specific environment. Each metric is read separately; one that could not be read is `{"error": true}` while the rest are returned. For `http_response_count`, `average` holds each series' sum over the period and `total` the sum of all of them. `min` and `max` are bounds for charting the series. # List environment logs Source: https://cloud.laravel.com/docs/api/environments/list-environment-logs https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/logs Get a list of logs for the given environment. # List environments Source: https://cloud.laravel.com/docs/api/environments/list-environments https://cloud.laravel.com/api-docs/api.json get /applications/{application}/environments Get a list of all environments for the given application. # Purge edge cache Source: https://cloud.laravel.com/docs/api/environments/purge-edge-cache https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/purge-edge-cache Purge the edge cache for all domains associated with the environment. By default everything cached for the environment is purged. Optionally provide a `path`, `prefix`, or `tag` to purge a subset of the cache. Only one of these may be provided per request. # Start environment Source: https://cloud.laravel.com/docs/api/environments/start-environment https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/start Start an environment and trigger a deployment. # Stop environment Source: https://cloud.laravel.com/docs/api/environments/stop-environment https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/stop Stop an environment and cancel any in-progress deployment. # Update environment Source: https://cloud.laravel.com/docs/api/environments/update-environment https://cloud.laravel.com/api-docs/api.json patch /environments/{environment} Update an environment. # Update vanity domain Source: https://cloud.laravel.com/docs/api/environments/update-vanity-domain https://cloud.laravel.com/api-docs/api.json put /environments/{environment}/vanity-domain Update the vanity domain for the environment. May only be done once every 30 minutes. # Create instance Source: https://cloud.laravel.com/docs/api/instances/create-instance https://cloud.laravel.com/api-docs/api.json post /environments/{environment}/instances Create a new instance for an environment. # Delete a managed queue failed job Source: https://cloud.laravel.com/docs/api/instances/delete-a-managed-queue-failed-job https://cloud.laravel.com/api-docs/api.json delete /instances/{instance}/failed-jobs/{jobId} Permanently remove a failed job from the given managed queue. # Delete instance Source: https://cloud.laravel.com/docs/api/instances/delete-instance https://cloud.laravel.com/api-docs/api.json delete /instances/{instance} Delete an instance. # Delete managed queue failed jobs Source: https://cloud.laravel.com/docs/api/instances/delete-managed-queue-failed-jobs https://cloud.laravel.com/api-docs/api.json delete /instances/{instance}/failed-jobs # Get instance Source: https://cloud.laravel.com/docs/api/instances/get-instance https://cloud.laravel.com/api-docs/api.json get /instances/{instance} Get the details of a specific instance. # List instance sizes Source: https://cloud.laravel.com/docs/api/instances/list-instance-sizes https://cloud.laravel.com/api-docs/api.json get /instances/sizes List all available instance sizes grouped by category. # List instances Source: https://cloud.laravel.com/docs/api/instances/list-instances https://cloud.laravel.com/api-docs/api.json get /environments/{environment}/instances Get a list of all instances for the given environment. # List managed queue failed jobs Source: https://cloud.laravel.com/docs/api/instances/list-managed-queue-failed-jobs https://cloud.laravel.com/api-docs/api.json get /instances/{instance}/failed-jobs Get a list of the jobs that have failed on the given managed queue. # Pause a managed queue Source: https://cloud.laravel.com/docs/api/instances/pause-a-managed-queue https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/pause Stop dispatching jobs to the queue's workers; queued messages are retained until it is resumed. # Purge a managed queue Source: https://cloud.laravel.com/docs/api/instances/purge-a-managed-queue https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/purge Permanently delete all messages currently in the queue. This cannot be undone. # Resume a managed queue Source: https://cloud.laravel.com/docs/api/instances/resume-a-managed-queue https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/resume Resume dispatching jobs to the queue's workers after it was paused. # Retry a managed queue failed job Source: https://cloud.laravel.com/docs/api/instances/retry-a-managed-queue-failed-job https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/failed-jobs/{jobId}/retry Re-queue a failed job so it is processed again. # Set the default managed queue Source: https://cloud.laravel.com/docs/api/instances/set-the-default-managed-queue https://cloud.laravel.com/api-docs/api.json post /instances/{instance}/default Make this queue the environment's default, used when a job does not specify a queue. # Update instance Source: https://cloud.laravel.com/docs/api/instances/update-instance https://cloud.laravel.com/api-docs/api.json patch /instances/{instance} Update an instance. # Laravel Cloud API Source: https://cloud.laravel.com/docs/api/introduction Use the Laravel Cloud API to manage applications, environments, and resources programmatically. The Laravel Cloud API lets you manage your Laravel Cloud organization, applications, environments, and resources programmatically. If you prefer a terminal workflow, the [Laravel Cloud CLI](/docs/api/cli) is built on top of this API and provides an interactive command-line experience. ## Base URL The base URL for the Laravel Cloud API is: ``` https://cloud.laravel.com/api ``` ## Authentication All API requests require a bearer token in the `Authorization` header. See [API authentication](/docs/api/authentication) for setup instructions. ## Make your first request Once you have a token, you can make requests directly to the API. The following example returns a JSON:API list of your applications: ```bash theme={null} curl https://cloud.laravel.com/api/applications \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Accept: application/json" ``` ## Next steps * Review [API authentication](/docs/api/authentication) for token setup and security guidance. * Explore [Laravel Cloud CLI](/docs/api/cli) if you want to work from the terminal. * Browse the endpoint reference in the API sidebar to see available resources and request schemas. # Get organization Source: https://cloud.laravel.com/docs/api/meta/get-organization https://cloud.laravel.com/api-docs/api.json get /meta/organization Get details about the currently authenticated organization. # List regions Source: https://cloud.laravel.com/docs/api/meta/list-regions https://cloud.laravel.com/api-docs/api.json get /meta/regions List all available cloud regions. # Create object storage bucket Source: https://cloud.laravel.com/docs/api/object-storage-buckets/create-object-storage-bucket https://cloud.laravel.com/api-docs/api.json post /buckets Create a new object storage bucket with an initial key. # Delete object storage bucket Source: https://cloud.laravel.com/docs/api/object-storage-buckets/delete-object-storage-bucket https://cloud.laravel.com/api-docs/api.json delete /buckets/{filesystem} Delete an object storage bucket. # Get object storage bucket Source: https://cloud.laravel.com/docs/api/object-storage-buckets/get-object-storage-bucket https://cloud.laravel.com/api-docs/api.json get /buckets/{filesystem} Get a specific object storage bucket. # List object storage buckets Source: https://cloud.laravel.com/docs/api/object-storage-buckets/list-object-storage-buckets https://cloud.laravel.com/api-docs/api.json get /buckets Get a list of all object storage buckets for the authenticated organization. # Update object storage bucket Source: https://cloud.laravel.com/docs/api/object-storage-buckets/update-object-storage-bucket https://cloud.laravel.com/api-docs/api.json patch /buckets/{filesystem} Update an object storage bucket. # Create secret Source: https://cloud.laravel.com/docs/api/secrets/create-secret https://cloud.laravel.com/api-docs/api.json post /secrets Create a new secret for the authenticated organization. The value must be sealed with the public key of the submitted key pair, both of which are returned by the secrets public key endpoint, before it is submitted. # Delete secret Source: https://cloud.laravel.com/docs/api/secrets/delete-secret https://cloud.laravel.com/api-docs/api.json delete /secrets/{secret} Delete a secret and detach it from every environment it is attached to. # Get secrets public key Source: https://cloud.laravel.com/docs/api/secrets/get-secrets-public-key https://cloud.laravel.com/api-docs/api.json get /secrets/public-key Get the active public key for the organization. The public key can be used to seal values before creating or update secrets. # List secrets Source: https://cloud.laravel.com/docs/api/secrets/list-secrets https://cloud.laravel.com/api-docs/api.json get /secrets Get a list of all secrets for the authenticated organization. # Update secret Source: https://cloud.laravel.com/docs/api/secrets/update-secret https://cloud.laravel.com/api-docs/api.json patch /secrets/{secret} Update a secret. A new value must be sealed with the public key of the submitted key pair before it is submitted. # Stripe Projects Source: https://cloud.laravel.com/docs/api/stripe-projects Provision Laravel Cloud infrastructure from the Stripe CLI. Laravel Cloud is a [Stripe Projects provider](https://marketplace.stripe.com/apps/laravel-cloud), enabling you or your AI agent to quickly set up, manage, and pay for your plan, applications, and resources directly from the Stripe Projects CLI. ## Getting Started Install the Stripe CLI and the projects plugin: ```bash theme={null} stripe plugin install projects stripe projects init ``` Browse available Laravel Cloud services: ```bash theme={null} stripe projects catalog laravel_cloud ``` Create an application: ```bash theme={null} stripe projects add laravel_cloud/application --config '{"name":"My App","repository":"owner/repo","region":"us-east-1"}' ``` The repository must exist in a connected GitHub, GitLab, or Bitbucket account. If you haven't connected a source control provider yet, run `stripe projects open laravel_cloud` to manage your connections. After provisioning, the application receives a public URL on a Laravel Cloud domain (for example, `https://my-app-main-xxxxx.laravel.cloud`). Provision a resource: ```bash theme={null} stripe projects add laravel_cloud/starter --name my-plan stripe projects add laravel_cloud/application --config '{"name":"My App","repository":"laravel/laravel","region":"us-east-1"}' stripe projects add laravel_cloud/mysql --name my-database ``` View credentials: ```bash theme={null} stripe projects env stripe projects env --reveal ``` ## Available Services ### Plans | Service | Pricing | Description | | - | - | - | | `starter` | \$5/mo + usage | Entry plan with Scale-to-Zero enabled by default and \$5 free monthly usage credits. **[First month free](/docs/free-trial) for new subscriptions.** | | `growth` | \$20/mo + usage | For production workloads with autoscaling, worker clusters, and preview environments. | ### Deployable Services | Service | Category | Description | | - | - | - | | `application` | Compute | Deploy a Laravel application from a Git repository | | `mysql` | Database | Managed [Laravel MySQL](/docs/resources/databases/laravel-mysql) with automated backups | | `valkey` | Cache | Managed [Laravel Valkey](/docs/resources/caches/valkey) cache | Deployable services are components of a plan. Provision a plan first, then add deployable services. ## Management ### Resource Removal ```bash theme={null} stripe projects remove laravel_cloud-mysql ``` ### Change Plan ```bash theme={null} stripe projects upgrade laravel_cloud/starter laravel_cloud/growth ``` ### Dashboard Access Each provisioned resource includes a Laravel Cloud dashboard link in its access configuration. Visit the dashboard for advanced management: logs, metrics, scaling, environment variables, and more. You can also open the dashboard directly: ```bash theme={null} stripe projects open laravel_cloud ``` ## Extended API To manage your applications and resources beyond the standard provisioning protocol, we recommend using the [Laravel Cloud API](/docs/api/introduction) and [Laravel Cloud CLI](/docs/api/cli). Available operations include: * **Plan switching**. Upgrade or downgrade between Starter and Growth * **Configuration updates**. Resize MySQL and Valkey instances * **Environment variables**. Set, get, and delete variables on environments * **Deployments**. Trigger builds and monitor deployment progress * **Scaling**. Adjust replica counts and compute sizes * **Logs**. Fetch recent log output * **Domains**. Manage Laravel Cloud and custom domains # Get usage Source: https://cloud.laravel.com/docs/api/usage/get-usage https://cloud.laravel.com/api-docs/api.json get /usage Get billing and usage data for the authenticated organization. # Create WebSocket application Source: https://cloud.laravel.com/docs/api/websocket-applications/create-websocket-application https://cloud.laravel.com/api-docs/api.json post /websocket-servers/{websocketServer}/applications Create a new application for a WebSocket cluster. # Delete WebSocket application Source: https://cloud.laravel.com/docs/api/websocket-applications/delete-websocket-application https://cloud.laravel.com/api-docs/api.json delete /websocket-applications/{websocketApplication} Delete a WebSocket application. # Get WebSocket application Source: https://cloud.laravel.com/docs/api/websocket-applications/get-websocket-application https://cloud.laravel.com/api-docs/api.json get /websocket-applications/{websocketApplication} Get a specific WebSocket application including credentials. # Get WebSocket application metrics Source: https://cloud.laravel.com/docs/api/websocket-applications/get-websocket-application-metrics https://cloud.laravel.com/api-docs/api.json get /websocket-applications/{websocketApplication}/metrics Get metrics for a specific WebSocket application. # List WebSocket applications Source: https://cloud.laravel.com/docs/api/websocket-applications/list-websocket-applications https://cloud.laravel.com/api-docs/api.json get /websocket-servers/{websocketServer}/applications Get a list of all applications for a specific WebSocket cluster. # Update WebSocket application Source: https://cloud.laravel.com/docs/api/websocket-applications/update-websocket-application https://cloud.laravel.com/api-docs/api.json patch /websocket-applications/{websocketApplication} Update a WebSocket application. # Create WebSocket cluster Source: https://cloud.laravel.com/docs/api/websocket-clusters/create-websocket-cluster https://cloud.laravel.com/api-docs/api.json post /websocket-servers Create a new WebSocket cluster with a default application. # Delete WebSocket cluster Source: https://cloud.laravel.com/docs/api/websocket-clusters/delete-websocket-cluster https://cloud.laravel.com/api-docs/api.json delete /websocket-servers/{websocketServer} Delete a WebSocket cluster and all its applications. # Get WebSocket cluster Source: https://cloud.laravel.com/docs/api/websocket-clusters/get-websocket-cluster https://cloud.laravel.com/api-docs/api.json get /websocket-servers/{websocketServer} Get a specific WebSocket cluster. # Get WebSocket cluster metrics Source: https://cloud.laravel.com/docs/api/websocket-clusters/get-websocket-cluster-metrics https://cloud.laravel.com/api-docs/api.json get /websocket-servers/{websocketServer}/metrics Get metrics for a specific WebSocket cluster. # List WebSocket clusters Source: https://cloud.laravel.com/docs/api/websocket-clusters/list-websocket-clusters https://cloud.laravel.com/api-docs/api.json get /websocket-servers Get a list of all WebSocket clusters for the authenticated organization. # Update WebSocket cluster Source: https://cloud.laravel.com/docs/api/websocket-clusters/update-websocket-cluster https://cloud.laravel.com/api-docs/api.json patch /websocket-servers/{websocketServer} Update a WebSocket cluster. # Applications Source: https://cloud.laravel.com/docs/applications Create, manage, and deploy applications on Laravel Cloud from starter kits or existing Git repositories. ## Introduction An application is the top-level unit for deploying and managing your code on Laravel Cloud. Applications can be created from official [Laravel starter kits](https://laravel.com/starter-kits) or from existing GitHub, Bitbucket, or GitLab repositories. Applications can contain many environments and resources. ## Creating applications Laravel Cloud offers two ways to create applications: 1. **From Starter Kits** - Bootstrap a new application using official Laravel starter kits 2. **From Existing Repository** - Import and deploy from your existing Git repository Both methods require selecting a region where your application will be deployed. Currently, an application can only be deployed to a single region at a time. Laravel Cloud will automatically create a default [environment](/docs/environments) for your application regardless of the creation method you choose. Applications cannot be transferred between organizations once created. Applications are permanently associated with the organization they are created in. ### Creating from starter kits Laravel Cloud supports creating applications from official [Laravel starter kits](https://laravel.com/starter-kits), allowing you to deploy a production-ready Laravel application in minutes without needing an existing repository. #### Available starter kits Laravel Cloud provides the following official starter kit templates: * **Laravel** - A new, empty Laravel application * **[React Starter Kit](https://laravel.com/docs/12.x/starter-kits#react)** - React, TypeScript, Inertia, shadcn/ui * **[Vue Starter Kit](https://laravel.com/docs/12.x/starter-kits#vue-customization)** - Vue, TypeScript, Inertia, shadcn-vue * **[Livewire Starter Kit](https://laravel.com/docs/12.x/starter-kits#livewire-customization)** - Livewire, Laravel Volt, Flux UI #### Creating from a starter kit When creating an application from a starter kit: 1. Select "Use a template" from the application creation page 2. Choose your desired starter kit template 3. Configure your Git provider account (if not already connected) 4. Set your repository name and choose visibility (private or public) 5. Assign an application name 6. Select your deployment region The starter kit will automatically create a new repository in your connected Git provider account, clone the official Laravel starter kit code, and set up your application for deployment. Starter kit applications work exactly like any other Laravel application on Laravel Cloud. Once deployed, you can customize, extend, and deploy changes just like applications created from existing repositories. ### Creating from existing repository When creating an application from an existing repository, you will need to select a source control repository that the application should be deployed from, assign the application a name, and select a region. Existing repositories can contain applications built with any of Laravel Cloud's supported frameworks and runtimes. If you have not already linked a source control provider account to your organization, you will be prompted to do so when you create your application. Typically, your Laravel Cloud organization structure should mirror your source control provider organization structure. After a source control provider has been authenticated, the repository (or repositories) selected become available for all users in the organization to view and create applications from. ### Regions Laravel Cloud currently supports the following application regions: * US East (Virginia) / `us-east-1` * US East (Ohio) / `us-east-2` * CA Central (Central) / `ca-central-1` * EU Central (Frankfurt) / `eu-central-1` * EU West (Ireland) / `eu-west-1` * EU West (London) / `eu-west-2` * Asia Pacific (Singapore) / `ap-southeast-1` * Asia Pacific (Sydney) / `ap-southeast-2` * Asia Pacific (Tokyo) / `ap-northeast-1` For minimal latency, you should ensure that your application and its associated resources exist within the same region. ## Deleting applications When deleting applications, all environments within that application will be deleted; however, resources such as databases, key-value stores ,and object storage buckets are not deleted, since they may be used by other applications within the environment. To delete these resources, navigate to your organization's **Resources** tab. ## Troubleshooting ### Reconnect Git repository Applications can lose their connection to a Git repository if Laravel Cloud's API access is revoked from within the source control provider. When this happens, your application's environments can no longer deploy your latest changes. Follow these steps to restore your Git connection: 1. Navigate to your applications **Settings** page. 2. Click the "Not connected" button next to "Git repository". 3. Click the "Source control provider" dropdown to select an existing source control provider or connect a new one by clicking "Add account". 4. Select the right repository, click "Set repository", then click "Save". Your application's Git repository is now restored and you can resume deploying fresh code to your environments. In most cases environment branches will be restored automatically; however, there may be some cases where environment branches need to be manually selected and saved via the environment **Settings** tab. # Changelog Source: https://cloud.laravel.com/docs/changelog See the latest Laravel Cloud updates, improvements, and platform changes. ## MySQL Storage Auto-Upsize MySQL storage auto-upsize Laravel MySQL databases can now automatically upsize their own storage. When a database starts running low on disk, Laravel Cloud increases its allocated storage automatically, while the database stays online and keeps serving queries. When a database reaches 90% of its allocated storage, Laravel Cloud increases its disk size by 50%, rounded to the nearest 5GB. You can set a maximum size that automatic upsizing will not grow past. Storage can grow but cannot shrink, and each database is upsized at most once every 6 hours. Automatic upsizing is enabled by default and can be turned off per database at any time. [Read the Laravel MySQL documentation](/docs/resources/databases/laravel-mysql) to learn more. ## Log Drains Log Drains Enterprise plans can now forward your application logs to an Amazon S3 bucket you own in real time. Ideal for long-term retention, compliance, or integration with your existing observability stack. [Learn more about log drains](/docs/services/log-drains/overview). ## Preview Environment Improvements A Laravel Cloud comment on a pull request confirming the preview environment deployed successfully, with links to visit the preview and view deployment logs Laravel Cloud's Deployments page now shows a row for every open pull request with a preview, including its branch, its latest commit, and a link to open it. Each preview carries its own settings for password protection, automatic deletion, and environment variables. Every preview gets fresh resources instead of pointing at production. It sleeps between reviews on scale-to-zero Flex sizes and is deleted automatically when its pull request merges or closes. Preview environments are now included on all plans. [Read the preview environments documentation](/docs/preview-environments) to learn more. ## Statamic Static Caching Laravel Cloud now supports Statamic's full-measure static caching. When your application requires `statamic/cms`, Cloud detects it at deploy time and configures NGINX to serve the pre-rendered HTML files in `public/static` directly, so cached pages are returned without ever reaching PHP. Form submissions and live previews continue to route to your application as usual. To get started, set `STATAMIC_STATIC_CACHING_STRATEGY=full` in your environment variables and deploy. You don't need to write any custom NGINX configuration, and applications that don't use Statamic are unaffected. The static cache lives on each instance's local filesystem and is cleared on each deployment. Since Statamic only invalidates the cache on the instance that handled a content change, additional replicas would continue serving stale pages. For this reason, when using full-measure static caching, you should run your App cluster on a single instance by setting its [autoscaling strategy](/docs/compute#autoscaling) to **None**, and scale vertically by choosing a larger instance size instead of adding replicas. [Read the Statamic static caching documentation](https://statamic.dev/static-caching) to learn more. ## Self-Hosted GitLab Connect a self-hosted GitLab instance to Laravel Cloud Private Cloud customers can now deploy applications from a GitLab instance their organization runs itself. Register Laravel Cloud as an OAuth application in your GitLab instance, enter the credentials under **Settings > Integrations > Self-hosted GitLab**, and Cloud reads your repositories and receives push events just as it does for GitLab.com. Self-hosted GitLab requires GitLab v16.4 or later. [Read the self-hosted GitLab documentation](/docs/private-cloud/self-hosted-gitlab) to learn more. ## Request Metrics Request counts, response codes, and timings in Laravel Cloud See your busiest pages, spot errors, and find slow responses directly in Laravel Cloud. The new Requests tab shows request counts, response codes, and timings by page, with filters for domain and time range. Open the Requests tab under Monitoring to explore your application’s activity. No packages or code changes required. ## Managed Database Users Manage database users Laravel Cloud now lets you create and manage additional users for your database clusters, so you no longer need to share the default credentials with every service and teammate. Choose read-only or read-write access, then limit each user to the databases they need. Cloud generates a secure password for each user and keeps their credentials available in the database cluster panel. You can update a user's access at any time or delete the user when it is no longer needed. Managed database users are available for Laravel MySQL, RDS MySQL, and RDS Postgres clusters. [Read the database users documentation](/docs/resources/databases/laravel-mysql#database-users) to learn more. ## Pre-Deploy Package Checks Pre-deploy package checks Laravel Cloud now detects missing or outdated packages before deployment. When you enable Laravel Octane, Inertia SSR, or Laravel Nightwatch, or attach a storage bucket, Cloud displays the required installation command next to the setting. Managed queues and scheduled tasks are covered too, including the framework versions each one requires. The notices follow your repository rather than your last deployment. Laravel Cloud now reads your `composer.lock` on every push, so once you install the package and push, the notice clears without waiting for a deploy to confirm it. Notices only appear for features you've actually enabled, and they do not prevent you from saving changes or starting a deployment. [Read the deployments documentation](/docs/deployments) to learn more. ## Scoped API Tokens Organization API tokens can now be scoped to specific permissions and restricted to an application or individual environments, instead of granting full org-level access. Only organization admins can create tokens, so engineers and agents get exactly the permissions their automation needs and nothing more. Existing tokens continue to work with no changes required. To change what a token can do, create a new one with the scope you need and revoke the old one. [Read the scoped API documentation](/docs/api/authentication.mdx#scoping-api-tokens) to learn more ## Managed Queues Improvements Managed Queues v2 Managed queues have been rebuilt from the ground up. Workers now wake in under a second when jobs arrive on an idle queue, down from around fifteen seconds, and creating a queue asks only for a name, a queue type, a memory size, and an autoscaling range. The polling interval, visibility timeout, and shutdown timeout settings are gone: Laravel Cloud delivers every job to your workers itself, so pickup, visibility, and scaling are measured rather than tuned. Two new capabilities land alongside the new runtime. FIFO queues deliver jobs in the exact order they were dispatched, built for order-sensitive workloads like payment processing and ledger updates. And queue compute now comes in two classes: Flex scales to zero and is priced exactly like today's queue compute, while Pro stays always on for steady throughput and jobs that run up to an hour, with no cold starts. Existing queues keep running unchanged. To upgrade one, update to a supported framework version (Laravel 11.55.0, 12.63.0, or 13.19.0 and newer), pick a new Flex or Pro size in the queue's settings, and deploy. [Read the queues documentation](/docs/queues) to learn more. ## Stage, Review, Ship Stage, Review, Ship Save changes, review them, then deploy when you're confident. Laravel Cloud now stages every configuration change with a persistent banner that shows exactly what's waiting, wherever you are in your environment. Expand it for a full diff and ship the whole batch in one action. Oh, and the canvas is no longer locked while resources provision. Keep working. Laravel Cloud will catch up. ## MySQL Scale to Zero MySQL Scale to Zero Laravel MySQL Flex databases can now scale to zero, sleeping when your database is idle so that you are not billed for compute. Storage stays online the whole time, so your data is always preserved. The next connection wakes the database automatically, and because every cluster is fronted by a proxy layer, that connection is held while compute resumes and forwarded once the database is awake. Waking adds only a few hundred milliseconds to the first query. Pair a Flex database that scales to zero with [application compute](/docs/compute#scale-to-zero) and a [Laravel Valkey cache](/docs/resources/caches/valkey#scale-to-zero) that scale to zero to minimize costs on your development environments, side projects, and even production environments that have periods of inactivity. Scale to Zero is available on the Flex sizes in all regions. Existing databases continue to run on their current size and pricing unchanged. [Read the Laravel MySQL documentation](/docs/resources/databases/laravel-mysql#scale-to-zero) to learn more. ## Secrets Manager Secrets Manager Laravel Cloud now includes a Secrets Manager for defining encrypted secrets at the organization level and linking them to one or more environments. Instead of copying shared values like third-party API tokens into each environment individually, you can define them once, link them where they're needed, and rotate them in a single place. Cloud injects secrets as environment variables during deployment. Secret values are write once, read never. Your browser encrypts each value before it is submitted, so plaintext never reaches Cloud's servers, and the dashboard never displays a saved value. Secrets are decrypted only when creating a deployment, with organization key material protected by AWS Key Management Service (KMS). [Read the secrets documentation](/docs/secrets) to learn more. ## First-Class Monorepo Support Monorepo support Laravel Cloud now automatically detects monorepos when you create a new application. If your repository contains multiple projects, Cloud presents the top-level directories so you can choose the one to deploy, and scopes all build and runtime operations, including commands and background processes, to that directory. If your monorepo holds more than one application, such as a frontend and a backend, create a separate Cloud application for each one and attach the same repository. Each application deploys from its own root directory and scales independently, with its own environment variables, instances, and domains. [Read the monorepo documentation](/docs/monorepos) to learn more. ## Symfony Support Symfony app on Laravel Cloud's UI Symfony app on Laravel Cloud's UI You can now deploy Symfony applications on Laravel Cloud. Cloud reads your`composer.json`, detects`symfony/framework-bundle`, and configures the runtime automatically using `php bin/console`. No changes are required to your application's code. Doctrine (Postgres and MySQL), Symfony Messenger with managed queues support, WebSockets via the Pusher protocol, Laravel Valkey caching, R2 object storage, and preview environments per pull request all work out of the box. Connect a database resource, and `DATABASE_URL`is injected automatically. Symfony 7.4 LTS and 8.x are supported on PHP 8.2 through 8.5. [Read the Symfony quickstart guide](/docs/quickstart#symfony) to get started. ## Expanded Outbound IP Addresses Laravel Cloud API We've provisioned additional outbound IP addresses in several regions to improve networking capacity and reliability. Over the coming weeks, Laravel Cloud will begin routing outbound requests through these new addresses. If you allowlist the IPs that Laravel Cloud uses for outbound requests—for example, to permit access to a third-party API, database, or firewall—update your rules to include the new addresses before they go live to avoid disruptions. The current, complete list is always available in our documentation and via the API. [Read the networking documentation](/docs/network#ip-addresses) to learn more. ## Improved Notifications Notifications Email notifications are now personal to each team member, allowing you to customize which events you care about across your organizations, applications, and environments. Slack notifications are configured at the organization level with a default channel and per-application overrides, so you can route different apps to different channels without overwhelming your team with noise. [Read the notifications documentation](/docs/notifications) to learn more. ## Deploy to Laravel Cloud with Stripe Projects Laravel Cloud x Stripe Projects Laravel Cloud is now available through Stripe Projects, a tool that lets you discover, provision, and pay for developer tools directly from the Stripe CLI. Provision, or let your agents provision, your Laravel Cloud infrastructure using a single command. Read our [Stripe Projects docs](/docs/api/stripe-projects) to get started. ## ElastiCache ElastiCache Provision fully managed AWS ElastiCache caches, available in both Valkey and Redis OSS, directly from Laravel Cloud. ElastiCache delivers high-throughput, low-latency performance backed by AWS infrastructure, with automatic failover, multi-AZ deployments, and in-place version upgrades. ElastiCache is available with Private Cloud. Choose from a range of node sizes and deployment options, from a single-AZ instance for development to multi-AZ clusters with automatic failover for production workloads. [Read the ElastiCache documentation](/docs/private-cloud/elasticache) to learn more. ## Scale to Zero and New Pricing Scale to Zero Laravel Cloud now offers a new generation of Flex compute that can scale to zero, sleeping when your application is idle and waking in under 500 milliseconds when a request arrives. Your scheduled tasks continue running and queued jobs keep processing while the environment sleeps. Flex compute, Serverless Postgres, and Laravel Valkey can sleep and wake together so you only pay for what you use. Alongside Scale to Zero, we've refreshed our plans: * The new **Starter plan** is \$5/mo with \$5 in monthly usage credits and a free first month. * Every paid plan now includes \$5 in monthly usage credits. * **Spending limits** let you set a hard monthly cap so your bill never exceeds your budget. * **Custom domains** are now counted per organization, with additional domains billed at \$0.25 per domain per month. [Read the compute documentation](/docs/compute#scale-to-zero) to learn more. ## Managed Queues Managed queues Managed queues are now generally available. Laravel Cloud provisions the queue, runs workers on dedicated instances, and automatically scales them based on the work waiting to be processed — including scaling to zero when your queue is idle, so you only pay for compute when jobs are actually running. Each managed queue is independent, with its own pool of workers, instance size, and scaling configuration. You also get a built-in failed jobs dashboard with retry tooling, so background work is isolated from your web traffic and easy to operate. [Read the queues documentation](/docs/queues#managed-queues) to learn more. ## HTTP Basic Authentication HTTP basic authentication Protect staging environments, preview environments, private demo environments, etc with HTTP basic authentication. When enabled, visitors must enter the username `admin` and the environment password before traffic reaches your application. This feature is available on the Growth plan or higher, and can help prevent unauthorized visitors or automated bots from waking hibernating environments. [Read the environment documentation](/docs/environments#http-basic-authentication) to learn more. ## Roles & Permissions Roles and permissions Give every member of your organization the right level of access with role-based access control. Basic RBAC is available on every plan with a set of predefined team roles designed to match how most teams already work. On the Business and Enterprise plans, Advanced RBAC unlocks custom roles, application and environment-level access, and the new Restricted role — perfect for contractors, auditors, or teammates who should only see a specific slice of your organization. [Read the roles and permissions documentation](/docs/rbac) to learn more. ## Dedicated Edge Network Enhancements Dedicated Edge Network rules Catch the traffic costing you money or causing problems. Surface top IPs and paths at your edge, turn them into firewall or cache rules in a click, and watch each rule take effect in real time. ## Mobile Cloud is Here Laravel Cloud on a phone: environment overview with project, repository, and Deploy The Laravel Cloud experience is now fine-tuned for any screen. Move between environments, manage resources, watch deployments, and ship releases from wherever you are. Perfect for on-the-go deployments and AI workflows. ## Redesigned Usage Page Redesigned Usage Page The Usage page has been redesigned to make it easier to understand what your organization is spending and where that spend is coming from. You can now review a cleaner summary of your current spend, bandwidth usage, credits, and billing alerts, then drill down into resource costs and application-level compute usage by environment. The new layout also makes it easier to spot the clusters, resources, and add-ons contributing to your bill during the selected billing period. [Read the usage documentation](/docs/usage) to learn more. ## Scheduled Autoscaling Scheduled autoscaling Scheduled autoscaling is now available on the Business and Enterprise plans. You can create one-time or recurring schedules that temporarily adjust your minimum and maximum replicas, as well as your CPU and memory thresholds, before predictable traffic arrives. This makes it easy to prepare for launches, promotions, business hours, and other recurring traffic patterns without manually changing your baseline scaling settings. Each schedule uses its own timezone, and Laravel Cloud automatically applies the one that matches the current time. [Read the compute documentation](/docs/compute#scheduled-autoscaling) to learn how to configure scheduled autoscaling. ## Sign In with GitHub Github SSO GitHub SSO is here. Sign in or create your account with GitHub, and since we already use that connection for source control, your repos come with you. Go from sign-up to first deploy faster than ever. ## Try Laravel Cloud for Free Try Laravel Cloud for Free Start shipping on Laravel Cloud with \$5 in free usage credits, automatically applied to your account the moment you sign up. Deploy your first applications, spin up databases, caches, and more, on us. Want a completely free trial? Our Starter plan has no subscription fee. Your \$5 in credits is all you need to get started, no questions asked. Credits are valid for 14 days. When they run out or expire, you're billed for what you use. [Sign up](https://cloud.laravel.com/sign-up) or [read the docs](/docs/free-trial) to learn more. ## Same Git Account, Multiple Organizations and Users Try Laravel Cloud for Free Git connections are now stored per user instead of per organization. The same Git account can be connected to multiple Cloud users and organizations at once. * **One user, many orgs.** Connect once and use your Git account across every organization you belong to. * **One git account, many Cloud users.** Connect the same git provider (e.g. your personal GitHub) to multiple Cloud user accounts. Each Cloud account and org stays separate, but they can all use the same git source. To use the new model, reconnect from your organization's git provider settings. [Learn more about source control connections](/docs/source-control). ## Laravel Cloud API: Programmable Infra for Teams and AI Agents Laravel Cloud API You can now manage your entire Laravel Cloud infrastructure programmatically with the Laravel Cloud API. Our API covers deployments, environments, databases, caches, object storage, and scaling for CI/CD integration, infrastructure-as-code workflows, and AI agents that provision resources or query status on your behalf. [Explore the API documentation](/docs/api/introduction). ## New CLI: Deploy and Manage from Your Terminal Laravel Cloud CLI You can now run and script Laravel Cloud operations directly from the command line. The CLI provides smart defaults for quick setup and full control when you need it. [Learn more in the CLI documentation](/docs/api/cli). ## MySQL 8.0 End of Life: Upgrade to 8.4 MySQL 8.4 Upgrade If your application is currently running on Laravel MySQL 8.0, please be aware that our MySQL 8.0 database version will reach end of life in April 2026 and will no longer receive security updates. To keep your database and application safe, we recommend upgrading to MySQL 8.4. MySQL 8.4 is the current long-term support release and ensures continued security updates, performance improvements, and long-term stability for your workloads on Laravel Cloud. Before upgrading, be sure to create a backup of your database. For complete upgrade instructions and guidance, please [visit the documentation](/docs/knowledge-base/upgrade-mysql-to-84). For additional context and walkthroughs, you can also watch this [Laravel Cloud Office Hours](https://www.youtube.com/live/S0DQmy8sBkY?si=JRmOqIHOSaRBAjpY) session. To avoid thinking about this in the future, we also recommend [setting up a maintenance window](/docs/resources/databases/laravel-mysql#maintenance-window) for your database. This allows Laravel Cloud to apply updates automatically at a time that works for you, so you can concentrate on shipping. * Sign in with Google SSO * Redesigned navigation * RDS Replicas, Postgres, Mysql now available for Private Cloud * File explorer for bucket storage ## Cloud API Expanded: Databases, Caches, Buckets, and WebSockets Cloud API Expanded The Laravel Cloud API now supports additional resources, including database clusters, caches, object storage buckets (and keys), and WebSocket clusters and applications. This expansion gives you programmatic access to more of your infrastructure, enabling you to automate provisioning, integrate Cloud into your CI/CD pipelines, and build custom tooling around your deployment workflows. Check out the [API documentation](/docs/api/introduction) to explore the available endpoints and learn how to get started. ## Valkey Now Generally Available Laravel Valkey Generally Available Laravel Valkey is now generally available on Laravel Cloud. With Valkey, you can provision fully managed, scalable cache instances for your Laravel applications with the same reliability and performance you expect from Cloud’s managed services. Because it is fully compatible with Redis protocols and commands, existing Redis users can switch to it directly. Building Laravel Valkey in-house has enabled us to tune every dial to ensure our solution outperforms standard Redis-compatible offerings: * Our benchmarks show Laravel Valkey delivers 20-50% lower latency than similar competitor offerings. * We’ve included a generous request size limit that is 5x to 20x larger than industry standards for the same price point as other providers. Get started by creating a new Valkey cache in Laravel Cloud. [Read the docs to learn more](/docs/resources/caches/valkey). ## Private Cloud Now Available Laravel Private Cloud [Laravel Private Cloud](https://cloud.laravel.com/enterprise) offers fully isolated, enterprise-grade infrastructure operated by Laravel. Get your own dedicated Kubernetes cluster in a private AWS account with dedicated compute, private networking, static outbound IPs, and optional managed RDS databases. **Key benefits:** * **Dedicated infrastructure:** Isolated compute and networking with predictable performance. * **Private Networking:** Connect to AWS services privately with reduced latency. * **Dedicated outbound IPs:** Customer-specific IPs for whitelisting and compliance. * **High availability:** Three nodes across availability zones with automatic failover. * **Built for compliance:** SOC 2 Type II certified, designed for HIPAA and PCI-DSS. * **Fully managed:** Laravel handles operations so you can focus on your product. Ideal for regulated industries and organizations with strict security or performance requirements. Includes Business Plan, 24/7 Artisan Support, and dedicated infrastructure. Custom pricing, typically cost-effective for \$2,000+/month workloads. [Check out the docs](/docs/private-cloud) or [contact sales](https://cloud.laravel.com/enterprise) to learn more. * Start/stop environments now in the Cloud API * Cloud API supports token expiration * Accessibility updates * Domain verification improvements * Fixed validation error on billing alerts ## New: Billing Alerts Billing Alerts Stay in control of your cloud spending with billing alerts. You can now configure notifications to alert you when you cross spending thresholds, helping you manage your budget proactively and avoid unexpected costs. Learn more in the [Billing Alerts documentation](/docs/billing-alerts). * Added cache details and metrics pages, with more consistent canvas actions * Renamed "filesystems" to "buckets" across the UI and API, and added a bucket details page * Valkey now supports configuring an eviction policy * Improved Valkey auto-upgrade * Improved billing alerts * Multiple small deployment and UI polish improvements * Require password to delete resources * Fixed WebSocket application "Edit settings" button * Fixed cache upgrade notification labeling ## Laravel Reverb-Powered WebSocket Is Now Generally Available Laravel Reverb WebSocket GA We're excited to announce that [WebSockets for Laravel Cloud](/docs/resources/websockets) is now generally available! Powered by Reverb, Laravel's first-party WebSocket server, you can now bring blazing-fast, scalable real-time communication to your applications. Deploying Reverb on Laravel Cloud is effortless. Just enable it in your project settings, and Cloud handles the rest, including providing you with a handy dashboard so you can keep an eye on your WebSocket connections. With Reverb, you can build real-time features like live notifications, chat systems, and collaborative tools with the simplicity and elegance you expect from Laravel. It works with Laravel's broadcasting system and is a drop-in replacement for services like Pusher and Ably. Check out the [Reverb documentation](/docs/resources/websockets) to get started. ## Valkey Now Available in Developer Preview Laravel Valkey Developer Preview Laravel Valkey is now available in developer preview on Laravel Cloud! Valkey is a high-performance, open-source key-value data store that serves as an alternative to Redis, offering the same performance speed and rich feature set you rely on. As a community-driven fork of Redis, Valkey maintains full compatibility with Redis commands and protocols, making it a drop-in replacement for your existing Redis workloads. From caching and session management to queues and real-time analytics, it delivers the performance and reliability your applications demand. During the developer preview, you can experiment with Valkey on Laravel Cloud and experience its benefits firsthand. We're committed to supporting open-source infrastructure, and Valkey represents our investment in providing you with the best tools for building modern web applications. [Enable Laravel Valkey in your project settings](https://cloud.laravel.com/sign-in) and let us know what you think, or [check out the docs](/docs/resources/caches/valkey) to learn more. ## Introducing the Canada Region Canada Region We're pleased to announce that Laravel Cloud is now available in the Canada region (ca-central)! Located in Central Canada, this new region brings Laravel Cloud closer to our Canadian users and anyone serving customers in Canada. With the Canada region, you can deploy your Laravel applications with reduced latency for Canadian users while ensuring compliance with data residency requirements. Deploying to Canada is simple: just select the ca-central region when creating a new project or provisioning new servers. All of Laravel Cloud's features are fully available in this new region, including automatic scaling, zero-downtime deployments, and managed databases. [See all the regions available in Laravel Cloud](/docs/applications#regions). ## gRPC Extension Now Available gRPC Extension Available By popular demand, Laravel Cloud now supports the gRPC PHP extension, our most requested addition. The gRPC extension enables high-performance, low-latency communication with services like Firebase, Google Cloud APIs, and other gRPC-based backends directly from your Laravel applications. To enable gRPC in your app, redeploy it. No additional configuration required. Check out all [available PHP extensions on Cloud](/docs/environments#php-extensions). * Business plan now available with increased domain limits * PHP 8.5 available (pdo\_sqlsrv support coming soon) * Serverless Postgres lower pricing * Redesigned build & deploy * Node 24 available * 25GB Laravel Redis cache option * Improved cache usage page * Fixed domains missing on Cloudflare not being marked as failed * Fixed cache errors on Redis by Upstash * Fixed dropdowns not closing properly * Fixed logs scroll bug * Fixed MySQL storage sync ## Laravel Cloud API Is Now Early Access Laravel Cloud API Early Access The Laravel Cloud API is now available in early access, giving you programmatic control over your Laravel Cloud infrastructure. Use it to automate deployments, manage environments, configure domains, and more from your own applications or scripts. With the early access release, you can manage key aspects of your Laravel Cloud setup, including applications, environments, deployments, domains, commands, instances, and background processes. [Contact our support team for EA](/docs/support) ## New Region: Hello, Ireland Ireland Region We're excited to announce that Laravel Cloud is now available in the Europe (Ireland) region. This expansion brings improved performance and reduced latency for applications serving users across Europe and the UK. Ireland joins our growing global infrastructure, offering you more flexibility to deploy your Laravel applications closer to your European audience. This location provides excellent connectivity throughout the region. To deploy to Ireland, select "Europe (Ireland)" when creating a new environment or server. Existing applications can be migrated to take advantage of this new region's benefits. [See all regions](/docs/applications#regions) ## Laravel Reverb-Powered WebSocket Clusters Laravel Reverb WebSocket Clusters We're excited to announce that [WebSockets for Laravel Cloud](/docs/resources/websockets), powered by Laravel Reverb, is now available in developer preview. This marks our first managed WebSocket offering, allowing you to easily add Reverb's real-time capabilities to your Laravel application without the complexities of managing your own infrastructure. All it takes is a few clicks in Cloud: select the desired number of concurrent connections, attach the resource to your environment, and you're off. [Learn more](/docs/resources/websockets) ## Advanced Rate Limit Rules Now Available For Business Plan Advanced Rate Limiting Customers on our [Business plan](https://cloud.laravel.com/pricing) now have access to advanced rate-limiting rules within their Web Application Firewall (WAF). These enhanced features provide more granular control over rate limiting, allowing you to customize triggers, actions, and bot protection settings to better secure your applications. With advanced rate limiting, you can define thresholds for request rates, set custom responses for rate-limited requests, and fine-tune bot protection mechanisms to distinguish between legitimate traffic and malicious bots. This level of control helps you protect your applications from abuse while ensuring a smooth experience for genuine users. [Contact our support team to upgrade](/docs/support) ## Set Up Email Notifications in Laravel Cloud Email Notifications You can now configure email notifications in Laravel Cloud to stay informed about important events across your organization and applications. Access notification preferences by clicking on Account under your profile and navigating to Notifications. Email notifications are available for a wide range of events, including organization changes, team member updates, API token activity, application and environment management, resource alerts, deployment status, and payment notifications. By default, you'll receive notifications for resource alerts, failed deployments, and failed payments. You can easily customize which notifications you receive by toggling your preferences on or off at any time. [Manage email notification preferences](https://cloud.laravel.com/profile/notifications) * Improved loading speed of source control repository selection * Laravel Valkey cache improvements * Updated pricing calculator * Add cache credentials to canvas * Fixed Slack channel names in notifications * UI fix for queue configurators * Fixed redirect on logout ## New Region: Welcome, Virginia New Virginia Region We're excited to announce that Laravel Cloud is now available in the US East (Virginia) region! This expansion means reduced latency and improved performance for applications deployed in the eastern United States. Virginia joins our growing list of regions, providing you with more options to deploy your Laravel applications closer to your users. This location offers excellent connectivity across the eastern seaboard. To deploy to Virginia, select "US East (Virginia)" when creating a new environment or server. Existing applications can be migrated to take advantage of this new region. [See all regions](/docs/applications#regions) ## Laravel Valkey is now Early Access Laravel Valkey Early Access Laravel Valkey is our new managed Redis offering that gives you a high-performance, fully managed key-value database right out of the box. With different sizes available, you can choose the right fit for your application. Laravel Valkey is available in early access. To request access, [contact our support team](/docs/support). ## Coming Soon to Laravel Cloud The Laravel Cloud team has a number of features launching this fall. Keep an eye out for Reverb, the Cloud API, a new region in Ireland (eu-west-1), and an Advanced Web Application Firewall. * Updated pricing for serverless Postgres * App performance improvements * [Laravel Cloud IPs now available in docs](/docs/network#ip-addresses) * App UI improvements: links in deployments, automation autofill * Slack channel renames * Typos in environment network settings and Bitbucket error message ## New Pricing New Pricing We’ve updated Laravel Cloud’s pricing plans. Starting on August 13, the Starter (formerly Sandbox), Growth (formerly Production), and Business plans now offer smarter usage-based billing and richer defaults like custom domains on Starter and Pro-class compute on Growth and Business. Bandwidth now scales with compute usage and is shared across environments, making billing more transparent and aligned with actual value. [Learn more about the new pricing](https://blog.laravel.com/laravel-cloud-more-features-smarter-pricing) ## Smart Autoscaling with Queue Clusters Queue clusters have been deprecated. Please see [Managed queues](/docs/queues#managed-queues). Smart Autoscaling with Queue Clusters Laravel Cloud now supports a third cluster type (in addition to [App and Worker clusters](/docs/compute)) built specifically for queue workloads. Available for testing in developer preview, these Queue clusters fully manage and autoscale Laravel queue workers, tracking CPU, memory, job throughput, and backlog in real time to determine how many workers and replicas your application needs. Autoscaling is latency‑driven: when queue wait time exceeds your threshold, capacity is automatically added, and once latency improves, the cluster scales back to reduce cost. This removes the guesswork of sizing queue workers manually while optimizing for both performance and savings. [Read the docs](/docs/queues) ## Laravel Cloud Is Now SOC2 Compliant SOC2 Compliance SOC 2 Type 2 is a compliance framework created by the American Institute of Certified Public Accountants (AICPA) that evaluates how organizations secure and protect customer data. The framework consists of five Trust Services Categories (TSCs) with specific criteria for assessing an organization's controls and service commitments. Laravel Cloud has achieved SOC 2 Type 2 attestation for Security, Confidentiality, and Availability. More information is available at [trust.laravel.com](http://trust.laravel.com/). ## New Region: Welcome, Sydney! New Sydney Region We're thrilled to announce that Laravel Cloud is now available in the Sydney (ap-southeast-2) region, expanding our global coverage to better serve customers in Australia and the broader Asia-Pacific area. This new region offers lower latency and improved performance for applications serving users in this part of the world. Deploying to Sydney is as simple as selecting "Asia Pacific (Sydney)" when creating a new app. Existing customers can continue using their current regions, while new projects targeting Australian and APAC users can benefit from this regional deployment option. [Learn more](/docs/applications#regions) * Enabled Slack notifications in private channels * Delete MySQL scheduled snapshots * Warnings when deleting environments with attached resources * Adds 6-hour option to logs * Slack channel pagination * Disable database upgrade button during upgrade ## MySQL is Production Ready MySQL is Generally Available You can now provision production‑ready MySQL instances with compute ranging from 1 CPU/512 MB RAM up to 8 CPU/32 GB RAM, and storage tiers from 5 GB to 1 TB. Automated daily backups are included, with retention configurable up to 30 days for standard plans and extended retention available on Enterprise plans. [Read the docs](/docs/resources/databases/laravel-mysql) ## Automated preview environments Automated preview environments Preview environments are now available on [Growth, Business, and Enterprise plans](https://cloud.laravel.com/pricing). For every pull request, Laravel Cloud automatically spins up a fully isolated production‑like environment. You can mirror your live app using either shared or dedicated databases, configure filters to limit previews by branch or PR, and run custom deploy steps such as migrations or seeders. Auto‑cleanup can be enabled to delete environments when PRs close or merge, so you only pay for active environments. These features help you catch bugs early, collaborate across teams, demo confidently, and ship with certainty. [Read the docs](/docs/preview-environments) ## Ship Faster With the New Starter Kits Ship with Starter Kits You can now deploy production‑ready Laravel applications in under five minutes using the new official [Laravel Starter Kits](https://laravel.com/starter-kits) for Laravel, Livewire, React, and Vue. Select a stack, choose a region, customize repository name and visibility, and Laravel Cloud handles the repo creation, deployment configuration, and infrastructure setup. All templates come directly from Laravel’s [official GitHub](https://github.com/laravel/laravel). No existing repository is required. This greatly simplifies launching demos, prototypes, or new apps without setup friction. Learn more about the [Laravel Starter Kits](https://youtu.be/y2FfKwcK_iU) * Improved repo searching when creating new apps * Added 6-hour period option for metrics viewing * Improved MySQL charts * Better validation running commands during deployments * Fix 404s in app for hibernation and page reloads * Log fixes * Responsive layout fixes ## One-Click Nightwatch Integration Laravel Cloud Nightwatch Integration You can now quickly [enable Laravel Nightwatch monitoring](/docs/environments#nightwatch-integration) in your Cloud environment canvas with a single click. This new integration runs Nightwatch across all your App and Worker clusters and automatically injects the correct `.env` settings so you can get up and running (or edit your sampling threshold) faster. [Start monitoring with Nightwatch](https://nightwatch.laravel.com/sign-up) ## Under Attack Mode Laravel Cloud Under Attack Mode We’ve enhanced DDoS protection with an optional Under Attack Mode you can enable during periods of unusual traffic. While DDoS attacks are automatically detected and mitigated, this mode provides an additional layer of protection when you want to safeguard your app proactively. When active, access to your app is restricted, and visitors are presented with a JavaScript challenge before they can reach your app. The feature automatically expires after 24 hours to help prevent unintentional enablement. To enable Under Attack Mode, head to your environment, click on Network, and then Web Application Firewall settings. [Learn how to set up Under Attack Mode](/docs/network#under-attack-mode) ## Improved Metrics and Charts Laravel Cloud Improved Metrics and Charts We’ve updated our metrics to offer a more detailed and granular view of resource usage. CPU and memory charts have been refined to highlight trends and spikes, enabling more informed decisions about scaling and optimization. For example, memory charts now display total cache storage usage instead of average cache usage, meaning that if you have one or more replicas, you will now see each replica’s memory usage instead of the average memory. [Check your app's performance](https://cloud.laravel.com/sign-in) ## MySQL Metrics Land as GA Nears You can now view real-time CPU, memory, and storage metrics for your MySQL databases. Navigate to your environment, click Resources, and then hit the Cluster card to see all metrics. This addition gives you a fuller picture of database performance and is one of several steps we’re taking as we move closer to MySQL's general availability. If you're using MySQL in Laravel Cloud, this brings deeper visibility and greater operational confidence. [Check your MySQL database performance](https://cloud.laravel.com/sign-in) * New 500gb cache type * Added notifications to command palette * Archive MySQL databases * Improved Slack notifications adding MySQL and Cache alerts * Improved speed on environments page * Cache and Database dialog minor fixes * Fix HTTP timeout validation message ## Visualize Replica Count You can now view a replica count chart in your environment’s Metrics tab that shows exactly when autoscaling occurs in your Laravel Cloud applications. The step chart visualizes how each of your App and Worker clusters scale from one to multiple replicas. You can also see when your application was scaled to zero and not incurring compute usage costs due to being stopped manually or hibernating automatically (requires Hibernation to be toggled on). This update helps provide clearer performance and billing insights for each of your Cloud environments. Laravel Cloud Replica Count [View your replica metrics](https://cloud.laravel.com/to/org/applications) ## More Flexible Caching Laravel Cloud’s Redis-compatible key-value stores can now be configured to scale up automatically when usage limits are met. Instead of hard limits that could lead to downtime and require manual intervention, caches can now upsize with zero downtime as they approach monthly data transfer or usage thresholds such as simultaneous connections, commands per second, record size, and request size. Opt in to auto-upsizing by toggling on the “Automatically Upgrade” option of your new or existing Laravel Cloud caches. Laravel Cloud Flexible Cloud Cache Sizing [Learn more about Laravel Cloud caches](/docs/resources/caches/valkey#automatic-upsizing) ## Slack Alerts [Slack notifications](/docs/notifications) now include a new “Resource Alerts” category for critical runtime issues. You’ll receive real-time alerts anytime CPU, RAM, or disk usage nears its limit or when your compute crashes, making it easier to identify and respond to issues quickly. Set up Slack notifications in Laravel Cloud and opt in to Resource Alerts to make sure you are the first to know when your applications are at risk of downtime or performance degradation. Laravel Cloud Slack Alerts [Connect Slack to Laravel Cloud](https://cloud.laravel.com/to/org/settings/notifications) * Show total cache storage usage instead of average cache usage * Tooltips for identifiers in usage section * Added source control disconnected notification * Updated usage to include resource identifiers * Users can now configure WWW domains as root domains * Save and Deploy now deploys with latest commit * Configure backup setings for Laravel Serverless Postgres * Fixed average calculation on replica count chart * Fixed network settings blank screen ## Slack Notifications Connect Laravel Cloud to your Slack workspace to receive notifications about your organization and application. Organization settings include notifications about resources (new database, new application, etc.) and membership requests. Application settings include notifications about deployment success, environment settings, domain verification and more. You can configure application and organization notification to go to specific channels. [Connect your Slack workspace to Laravel Cloud](https://cloud.laravel.com/to/org/settings/notifications) ## Improved Usage Page The Usage page now includes an Allowances tab that shows your overall utilization of your plan's included usage. The Applications tab now also includes bandwidth usage (requests & data transfer) for each application. Paired with Invoice Previews, you can now deeply understand usage across your applications. [View Your Usage](https://cloud.laravel.com/to/org/usage/applications) ## Pricing Calculator Our pricing calculator allows you to estimate your costs on Laravel Cloud, before you even start deploying. Choose from our preset options (personal blog, SaaS app, etc) or customize everything and choose the compute and resources that work best for your application. [Try the pricing calculator](https://cloud.laravel.com/pricing/calculator) ## Greater Cache & Response Header Control You now have greater control of over your cache and response headers. All `Cache-Control` and `Expires` headers set by your application now be fully respected. In addition, you can choose when to purge your Edge Network cache - either manually or automatically on each new deploy. You can also choose to bypass the cache entirely. Finally, you can also override certain response headers like `X-Frame-Options`, `X-Content-Type-Options`, and `Strict-Transport-Security` directly in the Cloud environment canvas. [Learn more](/docs/network#cache-control) ## Flexible Backup Retention Window Laravel Serverless Postgres now allows setting a backup retention window between 0 to 30 days. Previously it was a fixed 7-day window with no flexibility to change the window or opt-out. Choose a backup window that works for your application and save money on storage if your application doesn’t require backups at all. [Learn more](/docs/resources/databases/postgres) * Hibernation is now enabled by default for all new environments on the Sandbox plan. * Add infinite scrolling for Logs. * Introduced full page layout for database UI. * Added organization restricted, suspended, and terminated billing states. * Improved Invoice Preview UI. * Individual chart lines on Metrics pages can now be enabled / disabled. * Various logs UI fixes. * Various source control provider fixes. ## Replicate Environments Create copies of existing environments with all configuration intact. This is an important step towards the team shipping automatic preview environments. This allows you to quickly spin up testing environments, create staging replicas of production, or set up identical workspaces for team members. Replication saves time and ensures consistency across your development workflow. [Learn more](/docs/environments#replicate) ## Stop and Restart Environments Take manual control of your environment states with our new stop and restart functionality. Unlike hibernation (which happens automatically), this feature lets you explicitly pause environments when you don't need them and restart them when you do. Perfect for managing costs, scheduling maintenance, or controlling resources during your development cycles. [Learn more](/docs/environments#stop-and-restart) ## Invoice Previews Better predict your spend by viewing a preview of your current month’s invoice (to date). Previews include plan subscription, additional usage (after allowances), and discounts. [View Invoice Preview](https://cloud.laravel.com/to/org/usage/invoices) ## Inertia SSR We now support the ability to serve [Inertia](https://inertiajs.com/) based pages via [server-side rendering](https://inertiajs.com/server-side-rendering). Inertia SSR pre-renders your HTML server-side before sending it to the client, which can improve your application’s SEO. [Learn more](/docs/compute#inertia-ssr) ## Repository Connection Management A disconnected repo no longer leaves you hanging. You can now edit which repository is connected to your application. This enables recovery from disconnections that occur when repositories are deleted or access is revoked. After updating your repository, you can easily reconnect each environment to the appropriate branch, preserving all your settings and attached resources. [Learn more](/docs/applications#reconnect-git-repository) *** * Improved GitHub integration for enhanced reliability. * Added applications usage to the usage screen. * Improved domain verification workflow. * Improved error messages for running commands. * Enhanced tooltips and copy button usability. * Allow re-running commands * Added support for enabling "EU jurisdiction" when creating a bucket. * Improved validation to check if Octane is installed before enabling it. * Environments can now be "woken" from the hibernation state. * Fixed an issue where “Build Logs” and “Deploy Logs” were sometimes truncated prematurely, preventing error messages from being displayed. * Resolved an issue where deployment output was sometimes missing when a deployment failed. * Fixed issue with the "Create Application" modal when a repository was not selected during branch refresh. * Fixed Bitbucket link issue. * Resolved an issue where the deployment output might incorrectly display as "complete". * Fix the issue where changing the application’s avatar also disconnects its source control. * Prevent commands from being executed on stopped environments. * Resolved timeout issue when creating applications with source controllers managing thousands of repositories. Launched Laravel Cloud! # Compliance & Security Source: https://cloud.laravel.com/docs/compliance Learn about Laravel Cloud security practices, compliance controls, and protections for production apps. We're committed to providing a secure and compliant platform for your applications. We understand that security and compliance are critical for your business, and we're proud to have achieved industry-leading certifications. This page outlines our current compliance status and provides transparency into our security measures. ## Current compliance status ### SOC 2 Type 2 System and Organization Control 2 Type 2 (SOC 2) is a compliance framework developed by the American Institute of Certified Public Accountants (AICPA) that focuses on how an organization's services remain secure and protect customer data. The framework contains 5 Trust Services Categories (TSCs), which contain criteria to evaluate the controls and service commitments of an organization. Laravel Cloud has achieved SOC 2 Type 2 attestation for Security, Confidentiality, and Availability. More information is available at [trust.laravel.com](https://trust.laravel.com/?product=cloud). ### HIPAA The Health Insurance Portability and Accountability Act (HIPAA) sets national standards for protecting sensitive patient health information in the United States. Laravel Cloud supports HIPAA compliance for customers on our Enterprise and Private Cloud plans through a signed Business Associate Agreement (BAA) and the administrative, physical, and technical safeguards required to protect Protected Health Information (PHI). If your application handles PHI, contact our team at [cloud@laravel.com](mailto:cloud@laravel.com) to request a BAA before deploying to Laravel Cloud. More information is available at [trust.laravel.com](https://trust.laravel.com/?product=cloud). ### ISO 27001 Laravel Cloud has achieved ISO 27001 certification. This internationally recognized standard for information security management systems helps protect your data and ensure the confidentiality, integrity, and availability of our platform. ## What this means for you Our commitment to these compliance standards means you can trust Laravel Cloud to handle your sensitive data with the highest level of security and care. These certifications demonstrate our dedication to: * **Data Security:** Protecting your data from unauthorized access, use, disclosure, disruption, modification, or destruction. * **OWASP Top 10 coverage:** Any domain served through Laravel Cloud's edge network, default or custom proxied through Cloudflare, is protected by Cloudflare's [OWASP Core Ruleset](https://developers.cloudflare.com/waf/managed-rules/reference/owasp-core-ruleset/), filtering common injection, authentication, and data exposure attacks before they reach your application. * **Availability:** Ensuring the continuous operation of our platform and minimizing downtime. * **Confidentiality:** Maintaining the privacy of your data and preventing unauthorized access. * **Compliance:** Adhering to industry best practices and regulatory requirements. ## Stay updated We will continue to update this page with the latest information on our compliance progress. We encourage you to check back regularly for updates. If you have any questions regarding our compliance status, please don't hesitate to contact our support team at [cloud@laravel.com](mailto:cloud@laravel.com). We appreciate your trust in Laravel Cloud and are committed to providing you with a secure and compliant platform. # Compute Source: https://cloud.laravel.com/docs/compute Configure compute resources in Laravel Cloud, including app instances, workers, scaling, and background processes. ## Introduction Each environment deployed to Laravel Cloud runs on at least one App compute instance, which is assigned a specified amount of CPU processing power and available RAM. Your environment's App compute instance is responsible for handling incoming HTTP traffic to the environment. In addition, you may add dedicated worker compute instances to your environment to process queued jobs or execute other background processes. Compute resources assigned to an environment may be managed from the environment's infrastructure canvas dashboard. ## App cluster Your environment's App cluster represents the primary compute and infrastructure that will run your application. This compute cluster can serve web traffic, scale to zero, and manage long-running processes such as [queue workers](/docs/queues). Laravel and Symfony applications can also run scheduled tasks. To scale or customize your environment's App cluster, click the cluster in your environment's infrastructure canvas dashboard. ### Laravel Octane Laravel Octane is available for Laravel applications only. Laravel Cloud makes it easy to run your application using [Laravel Octane](https://laravel.com/docs/octane), which boots your application once and keeps it in memory for each request. When editing your App cluster, toggle on the “Use Octane as runtime” option. Then, save and deploy your environment and Laravel Cloud will build, configure, and serve your Laravel application using Laravel Octane and [FrankenPHP](https://frankenphp.dev/). Please review the [Laravel Octane documentation](https://laravel.com/docs/octane) to learn about the caveats you should keep in mind when building your application to run on Octane. Before enabling the Laravel Octane runtime, make sure Laravel Octane has been [added to your application](https://laravel.com/docs/octane#installation) via the Composer package manager. ### Inertia SSR Inertia SSR is available for Laravel applications only. Laravel Cloud also allows you to serve your [Inertia](https://inertiajs.com) based pages via [server-side rendering](https://inertiajs.com/server-side-rendering). Inertia SSR pre-renders your HTML server-side before sending it to the client, which can improve your application's SEO. When editing your App cluster, toggle on the "Use Inertia SSR" option. Then, save and deploy your environment and Laravel Cloud will render your Laravel application's templates using Inertia's SSR engine. In addition, if you are using one of Laravel's official [starter kits](https://laravel.com/docs/starter-kits), you should update your environment's build commands to use the `npm run build:ssr` command instead of `npm run build`: ```bash theme={null} npm run build:ssr ``` ## Worker clusters Worker clusters run background processes on compute that is separate from your App cluster and web traffic. See [Workers](/docs/workers) to learn how to create worker clusters and configure background processes. ## Autoscaling Laravel Cloud can automatically scale the compute resources attached to your environment based on demand, CPU usage, and memory usage. To configure your environment's autoscaling strategy, click on your environment's App or Worker compute cluster on the infrastructure canvas dashboard, and select the autoscaling strategy that is appropriate for your environment. For maximum flexibility, Laravel Cloud currently supports three different autoscaling strategies: * **None:** run your App / Worker compute on a single instance without autoscaling. * **Custom:** automatically scale your App / Worker compute clusters up and down horizontally within a specified minimum and maximum replica range. * **Unlimited:** automatically scale your App / Worker compute clusters up and down indefinitely based on demand. The maximum number of replicas depends on your [plan](/docs/pricing#plans). On the Growth plan, clusters may scale to 10 replicas by default. If you need more replicas, [contact support](/docs/support) to [request a higher limit](/docs/pricing#raising-plan-limits) without changing plans. After adjusting your environment's autoscaling strategy, re-deploy the environment in order for the changes to take effect. ### HTTP traffic autoscaling For App clusters, Laravel Cloud automatically scales HTTP applications based on real-time traffic pressure in addition to your configured CPU and memory thresholds. Laravel Cloud scales based on whichever limit is reached first. Laravel Cloud's ingress layer continuously tracks active requests currently being processed by your application and adds replicas when demand exceeds available capacity. For PHP applications, each replica's capacity is based on the amount of memory allocated to the application. Laravel Cloud estimates that each PHP worker uses approximately 30 MB of memory and can process one request at a time: ```text theme={null} workers per replica = floor(memory_mb / 30) desired replicas = ceil(active_requests / workers_per_replica) ``` For example, a 512 MB PHP application supports approximately 17 concurrent requests per replica. If active HTTP requests rise above that capacity, Laravel Cloud launches additional replicas; when traffic subsides, excess replicas are removed. JavaScript, Go, and Python applications use the same traffic-based scaling signal, but their per-replica capacity depends on the runtime, application configuration, and workload. Because this scaling signal is based on active requests instead of trailing CPU or memory metrics, faster response times reduce the number of replicas needed to serve the same amount of traffic. ### Scheduled autoscaling Scheduled autoscaling is available on the **Business** and **Enterprise** plans. It allows you to define time-based overrides for clusters that scale between a minimum and maximum number of replicas. This is useful for predictable traffic patterns like product launches, marketing campaigns, or business hours. Each scheduled override temporarily changes your cluster's: * minimum replicas * maximum replicas * CPU threshold * memory threshold Overrides may be configured as one-time or recurring schedules. Recurring schedules support daily, weekday, weekend, or weekly patterns, and each schedule uses its own timezone so the configured start and end times match the hours that matter to your team. If multiple schedules overlap, Laravel Cloud applies the most specific matching override. One-time schedules take precedence over recurring schedules. Among recurring schedules, schedules for specific days of the week take precedence over weekday or weekend schedules, and weekday or weekend schedules take precedence over daily schedules. Scheduled autoscaling changes are applied automatically around the configured boundary times, typically within about one minute. ### Scheduled autoscaling limitations * Scheduled autoscaling is only available for clusters that scale between a defined minimum and maximum replica count. * Recurring schedules must start and end on the same day. If you need an overnight window, create two schedules. * One-time schedules run once, then automatically stop applying after their scheduled window ends. ## Compute classes Laravel Cloud applications run on the latest generation of AWS Graviton EC2 servers with an optimized cost to performance ratio, allowing us to pass on best-in-class compute performance and pricing. Laravel Cloud offers two classes of compute: Lightweight and cost-efficient. Perfect for dev environments or applications that need the flexibility to support periodic traffic bursts. Larger compute sizes designed for sustained, heavy utilization. Best for large-scale, mission-critical production applications. Within each class, there are multiple sizes of CPU and RAM available. Prices vary by region - see [Plans and Pricing](/docs/pricing) for more information. ## Compute metrics Your environment's compute metrics may be viewed by navigating to the **Metrics** tab of your environment. When graphed, CPU and memory usage for your environment's App and Worker clusters will be averaged across all replicas. ## Scale-to-Zero Your environment can scale to zero when it does not receive an inbound network request to your application (port 8080) within a specified time limit, known as the sleep timeout. While an environment is sleeping, you will not be charged for its compute until it is woken up again. New Flex compute sizes wake in under 500 milliseconds when the environment receives a new inbound request, which is fast enough that your application's users will not notice. Legacy Flex sizes use the previous wake behavior and typically take 5-20 seconds to wake. You can enable Scale-to-Zero by clicking on your environment's App cluster on the infrastructure canvas dashboard, enabling the Scale to Zero toggle, saving the compute cluster settings, and re-deploying the environment. ### Scheduled tasks and queues For Laravel applications, a sleeping environment wakes automatically to run [scheduled tasks](/docs/scheduled-tasks) and process [queued jobs](/docs/queues), so nothing falls behind while your environment sleeps. Symfony scheduled tasks should run on an always-awake worker cluster. When your environment wakes for a scheduled task or a manual wake interval, it stays awake for the duration of the sleep timeout. Any inbound request resets this timer. Make sure your scheduled tasks and background processes can complete within that window. If a queued job is still running when the sleep timeout elapses, the App cluster will stop and the job may be interrupted. We recommend [managed queues](/docs/queues#managed-queues) for queued jobs so that background processing is never interrupted by Scale-to-Zero. ### Manual wake interval You may configure a manual wake interval to wake an environment on a fixed schedule, which is useful for background processes like self-managed `queue:work` processes that must run periodically. As with scheduled tasks, a wake interval shorter than your sleep timeout can keep the environment awake continuously. ### Worker clusters Each Worker cluster can either stay awake at all times or follow the App cluster and sleep alongside it. You may configure this behavior within the Worker cluster's settings. ### Limitations * Only Flex compute sizes can scale to zero. * Sub-500 millisecond wake times apply to new Flex sizes only. Legacy Flex sizes keep their previous wake behavior. ## Maintenance mode This section applies to Laravel applications. Symfony applications handle maintenance mode differently. By default, Laravel uses the `file` driver for maintenance mode. If you run `php artisan down` from the **Commands** tab, the maintenance mode state will not persist across deployments or apply to multiple replicas. To ensure a consistent maintenance mode state across your application and its replicas, set the maintenance mode driver to `cache` and use either a [database](/docs/resources/databases/laravel-mysql) or [Laravel Valkey (Redis-compatible)](/docs/resources/caches) as the maintenance mode state backend in your environment variables. ```ini theme={null} APP_MAINTENANCE_DRIVER=cache APP_MAINTENANCE_STORE=database ``` # Go deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/go Configure your Go application for production on Laravel Cloud. The [Go quickstart](/docs/quickstart#go) walks you through your first deployment to Laravel Cloud. Once your application is up and running, this guide will help you get it ready for production. We'll cover how your Go application should be compiled, started, and configured so that it runs smoothly on Cloud. ## Listen on the right port Cloud routes traffic to your application on the port set by the `PORT` environment variable, which is `3000` by default. Your application should read this value and leave the host out of its listen address: ```go theme={null} port := os.Getenv("PORT") log.Fatal(http.ListenAndServe(":"+port, mux)) ``` When you use a bare `:port` address with Go's `net/http` server, it listens on all of the available IPv4 and IPv6 interfaces. This matters because Cloud's startup probes reach your application over IPv6. If you use an IPv4-only listener such as `net.Listen("tcp4", ...)`, or a loopback-only address, Cloud won't be able to reach your application. If your application deploys successfully but still isn't reachable, take a look at the [deployment troubleshooting](/docs/deployments#deployment-succeeds-but-serves-no-traffic) guide. ## Compile during the build Cloud installs your Go modules automatically and pre-fills a build command based on your application's entrypoint. If your `main` package lives at the root of your repository, the default build command looks like this: ```sh theme={null} CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o app . ``` If your entrypoint lives in a directory such as `cmd/server`, Cloud will build that package instead. When your repository contains more than one entrypoint, you may select the one you would like to deploy. Cloud also sets `CGO_ENABLED=1` for you when it detects cgo dependencies or C source files. Of course, you're free to edit the command if your application has any additional requirements. The default start command, `./app`, runs the binary produced by your build. By compiling in your [build commands](/docs/environments#build-commands), your application starts quickly when a new instance boots or when your environment wakes up after [scaling to zero](/docs/compute#scale-to-zero), since there's nothing left to compile. If your application includes other executables, you should compile them during the build as well. For example, an application with both a server and a migration command might use the following build command: ```sh theme={null} CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o app ./cmd/server && CGO_ENABLED=0 go build -o migrate ./cmd/migrate ``` Remember to use `CGO_ENABLED=1` for any binary that requires cgo. And, if you change your server binary's name or output path, be sure to update your start command to match. ## Shut down gracefully When an instance stops, whether during a deployment or while scaling down, Cloud sends a `SIGTERM` signal to your process. To avoid cutting off requests that are still in progress, your application should handle this signal and wait for those requests to finish before exiting. If you are using a `net/http` server, you may use the following function with your application's handler: ```go theme={null} import ( "context" "errors" "log" "net/http" "os" "os/signal" "syscall" "time" ) func serve(handler http.Handler) { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt) defer stop() srv := &http.Server{Addr: ":" + os.Getenv("PORT"), Handler: handler} go func() { if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatal(err) } }() <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("HTTP shutdown: %v", err) } } ``` Call this function from `main`, and your process will keep running until `Shutdown` returns. You should keep your application's shutdown timeout shorter than your environment's **graceful shutdown timeout** so the rest of the instance has time to stop cleanly, since Cloud will terminate any process that is still running once that timeout has passed. ## Running behind the proxy Cloud handles TLS for you before forwarding requests to your application, so your server only needs to speak plain HTTP. Along the way, Cloud's proxy passes along the original request scheme in the `X-Forwarded-Proto` header and the client's address chain in the `X-Forwarded-For` header. Before relying on these headers to determine the request scheme or client IP address, you should configure your framework's trusted proxy settings. Frameworks such as Gin and Echo provide this configuration out of the box. In general, you should avoid trusting forwarded headers from arbitrary sources, since clients can set them to any value they like. ## Databases and caches When you attach a database or cache from the infrastructure canvas, Cloud injects a `DATABASE_URL` (`postgresql://...` or `mysql://...`) or `REDIS_URL` (`rediss://...`) variable into your application's environment. You may read these values with `os.Getenv`. For Postgres, you may pass the connection URL straight to [pgx](https://pkg.go.dev/github.com/jackc/pgx/v5/pgxpool): ```go theme={null} pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL")) if err != nil { log.Fatal(err) } defer pool.Close() ``` For Redis, [go-redis](https://pkg.go.dev/github.com/redis/go-redis/v9#ParseURL) can parse the URL for you, and it will automatically configure TLS when it sees the `rediss://` scheme: ```go theme={null} options, err := redis.ParseURL(os.Getenv("REDIS_URL")) if err != nil { log.Fatal(err) } client := redis.NewClient(options) defer client.Close() ``` The [MySQL driver](https://pkg.go.dev/github.com/go-sql-driver/mysql#Config) is a little different, since it expects its own DSN format rather than a URL. You may parse the connection URL and let `mysql.Config` build the DSN for you: ```go theme={null} import ( "database/sql" "errors" "net/url" "os" "strings" "github.com/go-sql-driver/mysql" ) func connectMySQL() (*sql.DB, error) { u, err := url.Parse(os.Getenv("DATABASE_URL")) if err != nil || u.Scheme != "mysql" || u.User == nil || u.Host == "" { return nil, errors.New("DATABASE_URL must be a MySQL connection URL") } config := mysql.NewConfig() config.User = u.User.Username() config.Passwd, _ = u.User.Password() config.Net = "tcp" config.Addr = u.Host config.DBName = strings.TrimPrefix(u.Path, "/") config.ParseTime = true return sql.Open("mysql", config.FormatDSN()) } ``` If your application needs any driver-specific options, you may add them to the configuration before opening the connection. ## Migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. If your application includes the `cmd/migrate` executable from the [build example](#compile-during-the-build), your deploy command is simply: ```sh theme={null} ./migrate ``` If you prefer a separate migration tool, install or compile it during your build, then use its command here instead. # Laravel deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/laravel Configure your Laravel application for production on Laravel Cloud. The [Laravel quickstart](/docs/quickstart#laravel) walks you through your first deployment to Laravel Cloud. Since Cloud already handles most of what a Laravel application needs in production, this guide focuses on the handful of decisions that are still yours to make, such as how your application is built, how your jobs are processed, and where your data lives. Each section links to the full documentation if you would like to dig deeper. ## Build your application Your environment's [build commands](/docs/environments#build-commands) run each time you deploy. Typically, they will install your production dependencies, compile your frontend assets, and cache your application's configuration: ```sh theme={null} composer install --no-dev npm ci --audit false npm run build php artisan optimize ``` You should run `php artisan optimize` as part of your build rather than in your deploy commands, so the cached files are baked into your deployment. If you are using Inertia SSR with one of Laravel's [starter kits](https://laravel.com/docs/starter-kits), use `npm run build:ssr` in place of `npm run build`. If your application installs private Composer packages, you will need to configure your credentials before running `composer install`. The [build commands](/docs/environments#build-commands) documentation shows how. And, if you prefer Yarn, pnpm, or Bun over npm, take a look at [Using Yarn, PNPM, or Bun](/docs/knowledge-base/using-yarn-bun-pnpm). ## Attach a database Nearly every Laravel application needs a database. To add one, click **Add database** on your environment's infrastructure canvas, then create or attach a [Laravel MySQL](/docs/resources/databases/laravel-mysql) or [Laravel Serverless Postgres](/docs/resources/databases/postgres) database. The database must be in the same region as your environment. Once the database is attached, Cloud injects `DB_HOST`, `DB_USERNAME`, `DB_PASSWORD`, `DB_DATABASE`, and the rest of your connection details into your environment, so Laravel connects to it without any additional configuration. Just redeploy your environment so the new variables take effect. Since your environment's filesystem is reset on every deployment, SQLite is [not supported](/docs/knowledge-base/sqlite) in production. If you have been using SQLite locally, Cloud's MySQL and Postgres databases are a great fit. ### Using your database as a cache Most Laravel applications don't need a dedicated cache. For light to medium workloads, Laravel's `database` cache and session drivers work great, and they keep your infrastructure simple, since there's one less resource to manage and pay for. To use them, point both drivers at your database in your environment variables: ```ini theme={null} CACHE_STORE=database SESSION_DRIVER=database ``` If your application grows to the point where it needs a dedicated cache, you may attach a [Laravel Valkey](/docs/resources/caches/valkey) cache by clicking **Cache** on your environment's canvas. Cloud will inject the connection details and set `CACHE_STORE` for you, so Laravel starts using the cache right away. ## Run migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live, so your database schema is ready by the time the new code starts serving requests: ```sh theme={null} php artisan migrate --force ``` Deploy commands must finish within 15 minutes. Keep in mind that any changes they make to the filesystem will not be kept, so they are best suited to tasks like migrations that write to external resources. You do not need to run `queue:restart` or `horizon:terminate` yourself, since Cloud restarts your queue workers and manages Horizon for you after every deployment. You should also avoid running `optimize:clear` and `storage:link` during deployment. The [unnecessary build and deploy commands](/docs/environments#unnecessary-build-and-deploy-commands) documentation explains why. ## Environment variables Cloud writes your environment variables to a `.env` file before your application starts, so Laravel reads them exactly the way it does on your local machine. You can manage these values from your environment's [settings](/docs/environments#environment-variables). In addition to the variables Cloud injects for your attached resources, you may define any variables your application needs. If you define a variable that Cloud also injects, your value takes precedence. Remember to redeploy after changing your environment variables so your application picks up the new values. ## Store files in object storage Your environment's [filesystem](/docs/environments#filesystem) is ephemeral, meaning it is reset each time you deploy. In addition, each replica of your application has its own disk, so a file written while handling one request may not be visible to the next. For user uploads and any other files your application needs to keep, attach a [bucket](/docs/resources/object-storage) to your environment. Cloud injects `FILESYSTEM_DISK` along with the bucket's S3-compatible credentials, so you can work with your files through Laravel's `Storage` facade just like you would locally. Before you do, add the `league/flysystem-aws-s3-v3` package to your application's dependencies: ```sh theme={null} composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies ``` ## Process queued jobs [Managed queues](/docs/queues) are the easiest way to process your application's queued jobs on Cloud. Cloud provisions the queue for you and automatically scales its workers based on how many jobs are waiting, so you do not need to manage any queue infrastructure yourself. Managed queues require a recent version of Laravel and the `aws/aws-sdk-php` package. You can find the exact requirements in the [managed queue documentation](/docs/queues#connect-your-application). When you deploy a managed queue, Cloud sets `QUEUE_CONNECTION=cloud` for your environment. From then on, any job dispatched without an explicit connection is sent to your managed queue, including jobs that were previously processed by the `database` or `redis` driver. If you would rather keep using your own queue driver, you may run `queue:work` processes on your App cluster or on a dedicated [worker cluster](/docs/workers#laravel-queue-workers) instead. ## Schedule tasks To run your application's [scheduled tasks](/docs/scheduled-tasks), enable the **Scheduler** toggle on your App cluster or on a worker cluster. Cloud will then invoke `schedule:run` every minute, just like a traditional cron entry. If your App cluster runs multiple replicas, you should use Laravel's `onOneServer` method for any task that should only run once. Otherwise, the task will run on every replica. And, if your environment [scales to zero](/docs/compute#scale-to-zero), don't worry: Cloud automatically wakes your environment so your scheduled tasks keep running on time. # Next.js deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/nextjs Configure your Next.js application for production on Laravel Cloud. The [Next.js quickstart](/docs/quickstart#next-js) walks you through your first deployment to Laravel Cloud. Since Cloud already knows how to build and start a Next.js application, this guide focuses on the handful of things that are still yours to decide, such as how your environment variables reach the browser, where your data lives, and how your database is migrated. Each section links to the full documentation if you would like to dig deeper. ## Choose a runtime version Cloud can run your Next.js application on Node.js, Bun, or Deno, and it detects the right runtime from the files in your repository. A `package-lock.json` file selects Node.js, a `bun.lock`, `bun.lockb`, or `bunfig.toml` file selects Bun, and a `deno.json` or `deno.lock` file selects Deno. If you are using Node.js, you may choose your version from the Runtime section of your environment's General Settings page. After changing it, redeploy your environment so the new version takes effect. Bun and Deno run on a fixed version, so there's nothing to choose. You can find the supported versions in the [Runtimes](/docs/runtimes#node-js-bun-and-deno) documentation. ## Build your application Your environment's [build commands](/docs/environments#build-commands) run each time you deploy. Typically, they will install your dependencies and compile your application: ```sh theme={null} npm ci --audit false npm run build ``` If you prefer Yarn, pnpm, or Bun over npm, take a look at [Using Yarn, PNPM, or Bun](/docs/knowledge-base/using-yarn-bun-pnpm). ## Start your application Cloud starts your application by running the `start` script defined in your `package.json` file, which is usually `next start`. If you are using the Deno runtime, Cloud runs `deno task start` instead. You may override the start command from your environment's deployment settings if needed. Cloud routes traffic to your application on the port set by the `PORT` environment variable. The `next start` command reads this variable automatically, so most applications work without any changes. However, if you have replaced `next start` with a custom server, such as an Express server in a `server.js` file, make sure that server reads `PORT` rather than listening on a hardcoded port. Otherwise, your deployment will succeed but won't receive any traffic. The [deployment troubleshooting](/docs/deployments#deployment-succeeds-but-serves-no-traffic) guide has more details. ## Environment variables You may add your environment variables from your environment's [settings](/docs/environments#environment-variables). Cloud sets them directly on your application's process, so your server code can read them from `process.env` just like it does locally. Variables prefixed with `NEXT_PUBLIC_` are also available in the browser, while all other variables stay on the server. Keep in mind that Next.js inlines `NEXT_PUBLIC_` values into your JavaScript when your application is built. Your build commands receive your environment variables through a `.env` file, so these values are available during the build, but you will need to redeploy whenever you change one so the new value is compiled into your application. In addition to your own variables, Cloud automatically sets `NODE_ENV=production` and `NEXT_PUBLIC_SITE_URL`, which contains your application's URL, on every deployment. ## Attach a database or cache When you attach a [database](/docs/resources/databases/postgres) or [cache](/docs/resources/caches/valkey) from your environment's infrastructure canvas, Cloud injects a `DATABASE_URL` or `REDIS_URL` connection string into your environment. Most database libraries and ORMs, including Prisma and Drizzle, accept these URLs directly. The [Node.js deploy guide](/docs/deploy-guides/nodejs#databases-and-caches) includes examples for several popular clients. Your environment's [filesystem](/docs/environments#filesystem) is reset each time you deploy, and each replica of your application has its own disk. Because of this, anything your application needs to share or keep, such as sessions or cached data, should live in an attached database or cache rather than on disk. The same applies to Next.js's own data cache and incremental static regeneration. By default, Next.js stores these on the local filesystem, so each replica keeps its own copy and the cache is cleared on every deployment. If your application relies on revalidated pages staying consistent across replicas, configure a [custom cache handler](https://nextjs.org/docs/app/api-reference/config/next-config-js/incrementalCacheHandlerPath) backed by your cache. ## Store files in object storage For user uploads and any other files your application needs to keep, attach a [bucket](/docs/resources/object-storage) to your environment as its default disk. Cloud injects the `AWS_BUCKET`, `AWS_ENDPOINT_URL`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` variables. When creating your S3 client with the AWS SDK for JavaScript, be sure to pass the endpoint explicitly: ```js theme={null} import { S3Client } from "@aws-sdk/client-s3"; const s3 = new S3Client({ region: process.env.AWS_REGION, endpoint: process.env.AWS_ENDPOINT_URL, }); ``` ## Run migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. For example, if you are using Prisma, your deploy command might look like this: ```sh theme={null} npx prisma migrate deploy ``` Keep in mind that deploy commands must finish within 15 minutes, and any changes they make to the filesystem will not be kept. # Node.js deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/nodejs Configure your Express, Hono, or other Node.js application for production on Laravel Cloud. The [Node.js quickstart](/docs/quickstart#node-js) walks you through your first deployment to Laravel Cloud. Once your application is up and running, this guide will help you get it ready for production. We'll cover how your Express, Hono, or other Node.js application should be built, started, and configured so that it runs smoothly on Cloud. ## Choose a runtime version Cloud can run your JavaScript application on Node.js, Bun, or Deno. There's nothing to configure here, since Cloud detects the right runtime from the files in your repository: | Runtime | Detected by | | - | - | | Bun | `bun.lock`, `bun.lockb`, or `bunfig.toml` | | Deno | `deno.json` or `deno.lock` | | Node.js | `package-lock.json` | If you are using Node.js, you may choose your version from the Runtime section of your environment's General Settings page. After changing it, redeploy your environment so the new version takes effect. It's also a good idea to keep the `engines` field in your `package.json` compatible with the version you select. Bun and Deno run on a fixed version, so there's nothing to choose. You can find the supported versions in the [Runtimes](/docs/runtimes#node-js-bun-and-deno) documentation. ## Listen on the right port Cloud routes traffic to your application on the port set by the `PORT` environment variable. This is `3000` by default, or the port you chose when creating your application. Your application should read this value and leave the host out of its listen call: ```js theme={null} app.listen(process.env.PORT || 3000); ``` When you don't pass a host, Node.js listens on all of the available IPv4 and IPv6 interfaces. This matters because Cloud's startup probes reach your application over IPv6. If you pass an IPv4-only host such as `0.0.0.0`, or a loopback-only host such as `127.0.0.1` or `localhost`, Cloud won't be able to reach your application. If you are using Hono on Node.js, you will start your server through `@hono/node-server`: ```js theme={null} import { serve } from "@hono/node-server"; serve({ fetch: app.fetch, port: Number(process.env.PORT) || 3000 }); ``` If your application deploys successfully but still isn't reachable, take a look at the [deployment troubleshooting](/docs/deployments#deployment-succeeds-but-serves-no-traffic) guide. ## Install and compile during the build By default, Cloud pre-fills a build command that installs your application's dependencies: ```sh theme={null} npm ci --audit false ``` If your application has a compilation step, such as a TypeScript build, simply add it to your [build commands](/docs/environments#build-commands): ```sh theme={null} npm ci --audit false npm run build ``` Prefer Yarn, pnpm, or Bun? You may swap these commands out by following the [Using Yarn, PNPM, or Bun](/docs/knowledge-base/using-yarn-bun-pnpm) guide. ## Set the start command Cloud also pre-fills a start command based on the `start` script or `main` entry in your `package.json`, such as `node server.js`. If neither of these points to a file, the start command falls back to `npm start`, `bun run start`, or `deno task start`, depending on your runtime. Your start command should run your compiled output directly with `node`, such as `node dist/server.js`. By keeping compilation in your build commands, your application starts quickly when a new instance boots or when your environment wakes up after [scaling to zero](/docs/compute#scale-to-zero), since there's nothing left to compile. Tools such as `nodemon`, `tsx watch`, and `ts-node` are great for development, but they shouldn't be used to run your application in production. ## Environment variables Cloud sets your environment variables directly on your application's process, so you can read them from `process.env` just like you normally would. There's no need for a loader such as `dotenv`. Your build commands receive the same variables through a `.env` file in the build context. In addition to your own variables, Cloud automatically sets `NODE_ENV=production` and `APP_URL`, which contains your application's URL, on every deployment. To add your own values, see the [environment variables](/docs/environments#environment-variables) documentation. ## Shut down gracefully When an instance stops, whether during a deployment or while scaling down, Cloud sends a `SIGTERM` signal to your process. To avoid cutting off requests that are still in progress, your application should handle this signal and wait for those requests to finish before exiting: ```js theme={null} const server = app.listen(process.env.PORT || 3000); process.on("SIGTERM", () => { server.close(() => process.exit(0)); setTimeout(() => process.exit(1), 25_000).unref(); }); ``` Here, `server.close` stops accepting new connections and invokes its callback once all of the active connections have ended. The fallback timer makes sure your process exits even if a connection lingers. You should keep this timer shorter than your environment's **graceful shutdown timeout** so the rest of the instance has time to stop cleanly, since Cloud will terminate any process that is still running once that timeout has passed. ## Running behind the proxy Cloud handles TLS for you before forwarding requests to your application, so your server only needs to speak plain HTTP. Along the way, Cloud's proxy passes along the original request scheme in the `X-Forwarded-Proto` header and the client's address chain in the `X-Forwarded-For` header. Before relying on these headers to determine the request scheme or client IP address, you should configure your framework's trusted proxy settings. In Express, you may tell your application to trust the proxy running alongside it, which allows `req.protocol` and `req.secure` to reflect the original scheme: ```js theme={null} app.set("trust proxy", 1); ``` Express's [proxy documentation](https://expressjs.com/en/guide/behind-proxies.html) describes the other available options. In general, you should avoid trusting forwarded headers from arbitrary sources, since clients can set them to any value they like. ## Databases and caches When you attach a database or cache from the infrastructure canvas, Cloud injects a `DATABASE_URL` (`postgresql://...` or `mysql://...`) or `REDIS_URL` (`rediss://...`) variable into your application's environment. Most popular libraries accept these URLs directly, so connecting usually takes just a line or two of code. For Postgres, you may pass the connection URL straight to [node-postgres](https://node-postgres.com/features/connecting): ```js theme={null} import pg from "pg"; const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL }); ``` For MySQL, [mysql2](https://sidorares.github.io/node-mysql2/docs) accepts the connection URL as well: ```js theme={null} import mysql from "mysql2/promise"; const pool = mysql.createPool(process.env.DATABASE_URL); ``` For Redis, [node-redis](https://redis.io/docs/latest/develop/clients/nodejs/) will automatically configure TLS when it sees the `rediss://` scheme: ```js theme={null} import { createClient } from "redis"; const client = createClient({ url: process.env.REDIS_URL }); await client.connect(); ``` If you are using an ORM such as Prisma or Drizzle, you may point its configuration at `DATABASE_URL` as well. ## Object storage When you attach a [bucket](/docs/resources/object-storage) as your environment's default disk, Cloud injects the `AWS_BUCKET`, `AWS_ENDPOINT_URL`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` variables. When creating your S3 client with the AWS SDK for JavaScript, be sure to pass the endpoint explicitly: ```js theme={null} import { S3Client } from "@aws-sdk/client-s3"; const s3 = new S3Client({ region: process.env.AWS_REGION, endpoint: process.env.AWS_ENDPOINT_URL, }); ``` You don't need to pass the access keys yourself, since the SDK reads them from the environment automatically. ## Migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. Keep in mind that deploy commands must finish within 15 minutes, and any changes they make to the filesystem will not be kept. For example, if you are using Prisma, your deploy command might look like this: ```sh theme={null} npx prisma migrate deploy ``` ## Background processes If your application needs a queue consumer or another long-running process alongside your web server, you may add it as a [custom background process](/docs/workers#custom-background-processes): ```sh theme={null} node worker.js ``` Cloud keeps an eye on your background processes and will automatically restart them if they exit unexpectedly. # Nuxt deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/nuxt Configure your Nuxt application for production on Laravel Cloud. The [Nuxt quickstart](/docs/quickstart#nuxt) walks you through your first deployment to Laravel Cloud. Since Cloud already knows how to build and start a Nuxt application, this guide focuses on the handful of things that are still yours to decide, such as how your application is rendered, how your configuration reaches the browser, and where your data lives. Each section links to the full documentation if you would like to dig deeper. ## Choose a runtime version Cloud can run your Nuxt application on Node.js, Bun, or Deno, and it detects the right runtime from the files in your repository. A `package-lock.json` file selects Node.js, a `bun.lock`, `bun.lockb`, or `bunfig.toml` file selects Bun, and a `deno.json` or `deno.lock` file selects Deno. If you are using Node.js, you may choose your version from the Runtime section of your environment's General Settings page. After changing it, redeploy your environment so the new version takes effect. Bun and Deno run on a fixed version, so there's nothing to choose. You can find the supported versions in the [Runtimes](/docs/runtimes#node-js-bun-and-deno) documentation. ## Build your application When you create your application, you choose whether Nuxt should run as a server or be generated as a static site. Your environment's [build commands](/docs/environments#build-commands) should match that choice. For a server-rendered application, install your dependencies and build: ```sh theme={null} npm ci --audit false npm run build ``` For static site generation, use `npx nuxt generate` in place of `npm run build`. If you prefer Yarn, pnpm, or Bun over npm, take a look at [Using Yarn, PNPM, or Bun](/docs/knowledge-base/using-yarn-bun-pnpm). ## Use the default Nitro preset Cloud serves Nuxt applications using Nitro's default `node-server` preset, which builds your server to `.output/server/index.mjs`. Nitro detects this preset automatically, so you usually don't need to configure anything. However, if your application was previously deployed to another host, your `nuxt.config` file may still set a host-specific `nitro.preset`, such as `vercel`, `netlify`, or `cloudflare`. The same is true if a `NITRO_PRESET` environment variable is set. In either case, the build will still succeed, but it produces output that Cloud can't serve, so your deployment goes live without receiving any traffic. Be sure to remove both before deploying. ## Start your application Cloud starts your application by running `.output/server/index.mjs` with `node`, `bun run`, or `deno run -A`, depending on your runtime. You may override the start command from your environment's deployment settings if needed. Cloud routes traffic to your application on the port set by the `PORT` environment variable, and Nitro's server reads this variable automatically. Nitro also listens on all available network interfaces unless you set a `HOST` or `NITRO_HOST` variable. Since Cloud's startup probes reach your application over IPv6, you should leave these variables unset rather than pointing them at an IPv4-only address such as `0.0.0.0`. If your application deploys successfully but still isn't reachable, take a look at the [deployment troubleshooting](/docs/deployments#deployment-succeeds-but-serves-no-traffic) guide. ## Environment variables You may add your environment variables from your environment's [settings](/docs/environments#environment-variables). Cloud sets them directly on your application's process, so your server code can read them just like it does locally. Variables prefixed with `NUXT_PUBLIC_` are available on the client, while all other variables stay on the server. Nuxt uses these variables to override the matching keys in your application's [runtime config](https://nuxt.com/docs/guide/going-further/runtime-config) when it starts, so you can change them without rebuilding your application. Just redeploy so the new values reach your instances. In addition to your own variables, Cloud automatically sets `NODE_ENV=production` and `NUXT_PUBLIC_SITE_URL`, which contains your application's URL, on every deployment. ## Attach a database or cache When you attach a [database](/docs/resources/databases/postgres) or [cache](/docs/resources/caches/valkey) from your environment's infrastructure canvas, Cloud injects a `DATABASE_URL` or `REDIS_URL` connection string into your environment. Most database libraries and ORMs, including Prisma and Drizzle, accept these URLs directly. The [Node.js deploy guide](/docs/deploy-guides/nodejs#databases-and-caches) includes examples for several popular clients. Your environment's [filesystem](/docs/environments#filesystem) is reset each time you deploy, and each replica of your application has its own disk. Because of this, anything your application needs to share or keep, such as sessions or cached data, should live in an attached database or cache rather than on disk. If you use Nitro's storage layer, you may configure it with a [Redis driver](https://nitro.build/docs/storage) that points at your cache. ## Store files in object storage For user uploads and any other files your application needs to keep, attach a [bucket](/docs/resources/object-storage) to your environment as its default disk. Cloud injects the `AWS_BUCKET`, `AWS_ENDPOINT_URL`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` variables. When creating your S3 client with the AWS SDK for JavaScript, be sure to pass the endpoint explicitly: ```js theme={null} import { S3Client } from "@aws-sdk/client-s3"; const s3 = new S3Client({ region: process.env.AWS_REGION, endpoint: process.env.AWS_ENDPOINT_URL, }); ``` ## Run migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. For example, if you are using Prisma, your deploy command might look like this: ```sh theme={null} npx prisma migrate deploy ``` Keep in mind that deploy commands must finish within 15 minutes, and any changes they make to the filesystem will not be kept. # Python deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/python Configure your Django, FastAPI, or Flask application for production on Laravel Cloud. The [Python quickstart](/docs/quickstart#python) walks you through your first deployment to Laravel Cloud. Once your application is up and running, this guide will help you get it ready for production. We'll cover choosing a production server, configuring your framework to run behind Cloud's proxy, and connecting to your databases, caches, and static files. ## Install dependencies Cloud installs your application's dependencies automatically during the build. To decide how, it looks for the following files in order and uses the first one it finds: | File | Installation | | - | - | | `uv.lock` | Export locked dependencies with uv, then install with pip | | `poetry.lock` | Export locked dependencies with Poetry, then install with pip | | `Pipfile.lock` | Export locked dependencies with Pipenv, then install with pip | | `requirements.txt` | Install with pip, including referenced requirements files | | `pyproject.toml` | Install the project with pip | You should list your production server, such as Gunicorn or Uvicorn, among these dependencies. When Cloud exports dependencies from a lockfile, it leaves out your development groups, so only what your application needs in production is installed. Packages are installed into a shared Python user directory, and their executables are added to your `PATH`, so you can call `gunicorn` or `uvicorn` directly from your start command. ## Run a production server Django and Flask applications use the Web Server Gateway Interface (WSGI) by default, while FastAPI applications use the Asynchronous Server Gateway Interface (ASGI). Cloud discovers your application's entrypoint and pre-fills a start command using a compatible server from your dependencies. Cloud knows how to generate commands for each of the following servers: | Server | Application interface | | - | - | | Gunicorn | WSGI | | uWSGI or pyuwsgi | WSGI | | Waitress | WSGI | | Granian | WSGI or ASGI | | Hypercorn | WSGI or ASGI | | Uvicorn | ASGI | | Daphne | ASGI | Cloud also recognizes Django projects that are configured for ASGI, as well as application factories in Flask and FastAPI projects. If none of these servers appear in your dependencies, Cloud falls back to Gunicorn for WSGI applications or Uvicorn for ASGI applications and pre-fills a `pip install --user` step in your build command to install it. That said, we recommend adding the server to your own dependencies so you stay in control of which version is installed. Your start command should always use a production server. Django's `runserver`, `flask run`, and reload modes such as `fastapi dev` or `uvicorn --reload` are great for development, but they shouldn't be used to run your application in production. ## Bind to the right interface Your server must listen on the port set by the `PORT` environment variable, which is `3000` by default. It must also accept IPv6 connections, since that is how Cloud's proxy and startup probes reach your application. The pre-filled Gunicorn command already takes care of this with `--bind [::]:$PORT`. If you are using Uvicorn, your start command should look like this: ```sh theme={null} uvicorn main:app --host :: --port $PORT ``` Of course, you should replace `main:app` with your own application's entrypoint. If your application is created by a factory, be sure to keep the `--factory` flag. Cloud may pre-fill Uvicorn's host as `--host ''`. When Uvicorn runs multiple workers, it uses an IPv4 socket for this value, which Cloud can't reach. Change it to `--host ::` so your application stays reachable as your worker count grows. If you are using a different server, make sure your start command still listens on IPv6. Listening only on the loopback interface, or on a hardcoded port, will also prevent Cloud from reaching your application. If your application deploys successfully but still isn't reachable, take a look at the [deployment troubleshooting](/docs/deployments#deployment-succeeds-but-serves-no-traffic) guide. ## Worker count Cloud sets the `WEB_CONCURRENCY` environment variable based on the resources allocated to your app instance. Django and Flask applications receive `(2 × whole CPU cores) + 1` workers, capped so that each worker has a 150 MiB memory budget. FastAPI applications receive one worker per whole CPU core. Either way, your application always receives at least one worker. Gunicorn and Uvicorn read `WEB_CONCURRENCY` automatically. If you are using another server, you will need to set its worker count option yourself. To change the number of workers, you may override `WEB_CONCURRENCY` in your [environment variables](/docs/environments#environment-variables) or pass your server's worker count flag directly. If your application uses a lot of memory per worker, you may want to lower the count. ## Shut down gracefully When an instance stops, whether during a deployment or while scaling down, Cloud sends a `SIGTERM` signal to your server. Gunicorn and Uvicorn both handle this signal gracefully by letting active requests finish before exiting. You should keep your server's shutdown deadline shorter than your environment's **graceful shutdown timeout** so the rest of the instance has time to stop cleanly. Gunicorn's `--graceful-timeout` option defaults to 30 seconds, while Uvicorn provides a `--timeout-graceful-shutdown` option. If your requests need more time to complete, adjust both your server's deadline and your environment's timeout. ## Running behind the proxy Cloud handles TLS for you before forwarding requests to your application, so your server only needs to speak plain HTTP. Along the way, Cloud's proxy passes along the original request scheme in the `X-Forwarded-Proto` header and the client's address chain in the `X-Forwarded-For` header. Before relying on these headers, you should configure your server's or framework's trusted proxy settings. For Django, add the following to your `settings.py` file so that `request.is_secure()` correctly recognizes HTTPS requests that arrive through Cloud's proxy: ```python theme={null} SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") ``` This setting also allows Django's HTTPS redirects and other secure request checks to use the original scheme. If you also run the same application behind a different proxy, be sure to review Django's [proxy setting documentation](https://docs.djangoproject.com/en/5.2/ref/settings/#secure-proxy-ssl-header) for its trust requirements. ## Django environment variables New Django environments include a securely generated `SECRET_KEY`, which you are free to edit. If Cloud can discover your settings module in your repository, it will also set `DJANGO_SETTINGS_MODULE` for you. In addition, Cloud provides `DEBUG=false`, along with comma-separated `ALLOWED_HOSTS` and `CSRF_TRUSTED_ORIGINS` values based on your environment's active domains. However, Django doesn't read these variables on its own, so you will need to add the following to your `settings.py` file: ```python theme={null} import os SECRET_KEY = os.environ["SECRET_KEY"] DEBUG = os.environ.get("DEBUG", "false").lower() == "true" ALLOWED_HOSTS = [ host.strip() for host in os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",") if host.strip() ] CSRF_TRUSTED_ORIGINS = [ origin.strip() for origin in os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",") if origin.strip() ] ``` These values automatically include any [custom domains](/docs/domains) you have added. Note that `ALLOWED_HOSTS` contains plain hostnames, while `CSRF_TRUSTED_ORIGINS` includes the `https://` scheme. You may override any of these variables in your [environment settings](/docs/environments#environment-variables), but you should always keep debug mode disabled in production. ## Databases and caches When you attach a database or cache from the infrastructure canvas, Cloud injects a `DATABASE_URL` (`postgresql://...` or `mysql://...`) or `REDIS_URL` (`rediss://...`) variable into your application's environment. You may read these values from `os.environ`. Django doesn't read `DATABASE_URL` on its own, but the [dj-database-url](https://github.com/jazzband/dj-database-url) package makes it easy. Add it to your dependencies along with the appropriate database driver, then configure your database like so: ```python theme={null} import dj_database_url DATABASES = {"default": dj_database_url.config()} ``` If you are using SQLAlchemy, you will need to tell it which driver you installed. For example, if you are using Psycopg 3 with a Postgres database: ```python theme={null} import os from sqlalchemy import create_engine from sqlalchemy.engine import make_url url = make_url(os.environ["DATABASE_URL"]) engine = create_engine(url.set(drivername="postgresql+psycopg")) ``` For Redis, [redis-py](https://redis.readthedocs.io/en/stable/connections.html) will automatically configure TLS when it sees the `rediss://` scheme: ```python theme={null} import os import redis cache = redis.from_url(os.environ["REDIS_URL"]) ``` ## Migrations Database migrations belong in your environment's [deploy commands](/docs/environments#deploy-commands). Cloud runs these commands just before your new deployment goes live. If one of them fails, Cloud cancels the rollout. New Django environments start with a migration command that is commented out. When you connect a database, Cloud enables it for you automatically, as long as you haven't customized your deploy commands. If you have, simply add the migration step yourself: ```sh theme={null} python manage.py migrate ``` If you are using Alembic or Flask-Migrate, your deploy command will be `alembic upgrade head` or `flask db upgrade`, respectively. ## Static files ### Django Cloud provides the following environment variables to Django applications, both during the build and while your application is running: ```ini theme={null} STATIC_ROOT=/var/www/html/public/static STATIC_URL=/static/ ``` Since Django doesn't read these variables on its own, you should add the following to your `settings.py` file, using your project's existing `BASE_DIR`: ```python theme={null} import os STATIC_ROOT = os.environ.get("STATIC_ROOT", BASE_DIR / "staticfiles") STATIC_URL = os.environ.get("STATIC_URL", "/static/") ``` The fallback values let you use the same settings on your local machine. Next, add the `collectstatic` command to your [build commands](/docs/environments#build-commands) so your assets are collected into `STATIC_ROOT`: ```sh theme={null} python manage.py collectstatic --noinput ``` Cloud pre-fills this command for you when it detects a Django project with an uncommented `STATIC_ROOT` setting or a WhiteNoise dependency. If your build commands don't include it, simply add it alongside your existing commands. Running it during the build ensures the collected files are included in your deployment. With these defaults in place, Cloud's Nginx server serves your collected files under `/static/` on your application's domain, as long as you are using Django's local static file storage. For example, `css/app.css` will be available at `https://your-app.laravel.cloud/static/css/app.css`. There's no need for object storage with this setup. If you would like to change either value, you may override these variables in your environment's [environment variables](/docs/environments#environment-variables). Since Cloud serves files from `/var/www/html/public`, a different URL prefix needs to match the directory layout. For example, you could use `STATIC_ROOT=/var/www/html/public/assets` with `STATIC_URL=/assets/`. To serve files from outside the public directory, you may configure [WhiteNoise](https://whitenoise.readthedocs.io/en/stable/django.html) to serve them through your application, or use a Django storage backend for [object storage](/docs/resources/object-storage). Keep in mind that changing these environment variables won't reconfigure Nginx or upload your files to object storage for you. ### Flask and FastAPI The environment variables described in the previous section only apply to Django. Flask serves its `static` directory at `/static` by default, while FastAPI requires you to mount a directory using [`StaticFiles`](https://fastapi.tiangolo.com/tutorial/static-files/). Neither framework needs any additional environment variables to serve static files. # Ruby and Rails deploy guide Source: https://cloud.laravel.com/docs/deploy-guides/ruby Configure your Ruby or Ruby on Rails application for production on Laravel Cloud. The [Ruby and Rails quickstart](/docs/quickstart#ruby-and-rails) walks you through your first deployment to Laravel Cloud. Once your application is up and running, this guide will help you get it ready for production. We'll cover preparing your repository, running Puma, connecting your databases, and handling assets, uploads, and background jobs. Most of the guide focuses on Ruby on Rails, but if you are deploying another Ruby or Rack application, be sure to read [Other Ruby and Rack applications](#other-ruby-and-rack-applications) as well. ## Prepare your repository Cloud detects a Ruby application when it finds a `Gemfile` in your application directory. You should commit both your `Gemfile` and `Gemfile.lock`, and make sure they include your production server and database adapter. For Rails applications, keep the generated `config/application.rb`, `config/environment.rb`, and `bin/rails` files in your repository, since Cloud uses them to recognize the framework. Your application runs on Linux with ARM64 processors. If your lockfile only lists the platforms for your development machine, add Cloud's platform locally and commit the updated lockfile: ```sh theme={null} bundle lock --add-platform aarch64-linux ``` Cloud accepts lockfiles that include the `aarch64-linux`, `aarch64-linux-gnu`, or generic `ruby` platform. If the application creation form reports a missing platform, push your updated lockfile and refresh the repository scan before continuing. If your application lives in a [monorepo](/docs/monorepos), select the directory that contains your `Gemfile`. Cloud keeps the surrounding repository available, so dependencies such as sibling path gems continue to work. ## Choose a Ruby version Cloud supports Ruby 3.2, 3.3, 3.4, and 4.0, with Ruby 3.4 as the default. The simplest way to choose your version is with a `.ruby-version` file: ```text theme={null} 3.4 ``` Cloud reads your version declaration from each deployment's commit. It checks `.ruby-version` first, then the `RUBY VERSION` section of `Gemfile.lock`, the `ruby` declaration in your `Gemfile`, `.tool-versions`, and finally `mise.toml`. A pinned version selects a major and minor release line, while a `Gemfile` version constraint selects the lowest supported release line that satisfies it. If your repository doesn't declare a version, you may select one from your environment's **General Settings** instead. If you declare a version Cloud doesn't support, the deployment stops before building. You can find more details in the [Ruby runtime](/docs/runtimes#ruby) documentation. It's a good idea to keep your Ruby declarations consistent with one another. In particular, if your `Gemfile` requires an exact patch version, it must match the Ruby patch version Cloud installs, or Bundler will reject the build. ## Install dependencies Cloud installs your gems automatically before running your [build commands](/docs/environments#build-commands). It uses the Bundler version recorded under `BUNDLED WITH` in your `Gemfile.lock`, or the Bundler version that ships with the runtime if that section is missing. Gems are installed using Bundler's deployment and frozen modes, so you should update your dependencies locally and commit the lockfile rather than running `bundle update` during deployment. Be sure that every gem your application needs in production lives outside of the excluded groups, including `puma`, your database adapter, and any gems used for background jobs or building assets. By default, Cloud skips the `development` and `test` groups. You may change which groups are installed using your [environment variables](/docs/environments#environment-variables) or [linked secrets](/docs/secrets): ```ini theme={null} BUNDLE_WITHOUT=development:test BUNDLE_WITH=production ``` If you need every ordinary group installed, set `BUNDLE_WITHOUT` to an empty value. Cloud applies these settings while installing your gems and keeps the same group configuration at runtime. Remember to redeploy after changing them. ## Run a production server ### Rails Cloud pre-fills your Rails start command using your application's binstub, when it exists: ```sh theme={null} bundle exec bin/rails server -b '::' -p $PORT ``` If your application doesn't have a `bin/rails` binstub, Cloud uses `bundle exec rails server` with the same bind and port options. Either way, keep `puma` in your production dependencies so Rails can start its server. Your server must listen on the port set by the `PORT` environment variable, which is `3000` by default, and it must accept IPv6 connections. This matters because Cloud's startup probes reach your application over IPv6. If you change the start command, be sure to keep the `::` bind, since an IPv4-only or loopback-only listener will prevent it from reaching your application. If you would rather start Puma directly, replace the `port` or `bind` directive in your `config/puma.rb` file with the following: ```ruby theme={null} bind "tcp://[::]:#{ENV.fetch('PORT', '3000')}" ``` Then, set your start command to: ```sh theme={null} bundle exec puma -C config/puma.rb ``` Puma should have a single listener for your application's port, so remove any other `port` or `bind` directives from your configuration. You should also keep Puma running in the foreground. ### Procfile commands If your repository includes a `Procfile`, Cloud uses its `web` command as your initial start command instead of the framework default. For example: ```text theme={null} web: bundle exec puma -C config/puma.rb worker: bundle exec sidekiq release: bin/rails db:prepare ``` If you use this example, remember to configure the IPv6 listener in `config/puma.rb` as described in the previous section. For Rails applications, Cloud also offers the `release` command in your deployment settings, and your other processes as background process suggestions. It doesn't run your entire Procfile automatically, so be sure to review these suggestions and configure the ones you need in your environment. ## Rails environment variables New Rails environments include a securely generated `SECRET_KEY_BASE`, which you are free to edit. You should keep this value the same across deployments so your users' existing signed cookies and sessions stay valid. If you are migrating an existing application, use its current secret. Cloud also provides the following production defaults: | Variable | Value | | - | - | | `RAILS_ENV` | `production` | | `RACK_ENV` | `production` | | `BUNDLE_WITHOUT` | `development:test` | | `DISABLE_SPRING` | `1` | | `RAILS_LOG_TO_STDOUT` | `1` | Cloud sets your environment variables on your application's process and makes them available to your build commands, so you can read any custom settings from `ENV` just like you do locally. If you define a variable yourself, your value takes precedence over both linked secrets and the injected defaults. ### Encrypted credentials If your application uses encrypted Rails credentials, add the matching `RAILS_MASTER_KEY` to your environment variables or [Secrets Manager](/docs/secrets). Be sure to use the key for the credentials file your production configuration actually loads, such as `config/credentials.yml.enc` or `config/credentials/production.yml.enc`. Keep in mind that `SECRET_KEY_BASE` is only used to sign your application's data. It can't decrypt your credentials, so it doesn't replace `RAILS_MASTER_KEY`. If your production configuration explicitly enables `config.require_master_key`, Cloud will check for a key before building your application. ## Databases When you connect a [Postgres](/docs/resources/databases/postgres) or [MySQL](/docs/resources/databases/laravel-mysql) database from your environment's infrastructure canvas, Cloud provides a `DATABASE_URL` variable containing a `postgresql://` or `mysql2://` URL for Rails. Be sure to include the `pg` gem for Postgres or the `mysql2` gem for MySQL in your production bundle. Rails reads `DATABASE_URL` automatically and merges it with your `config/database.yml` file. However, an explicit `url:` in that file takes precedence, so if your configuration still contains a URL from a previous host, remove it so Rails uses Cloud's connection instead. You should always use a managed database in production. Since your environment's [filesystem](/docs/environments#filesystem) is ephemeral, a SQLite file stored on an instance can't be shared across replicas and won't survive your next deployment. ### Solid Cache, Solid Queue, and Solid Cable Rails applications may use separate production connections named `cache`, `queue`, and `cable`. Cloud detects these connections in your `config/database.yml` file, and when you attach your primary database, it creates a separate database for each one it finds. These databases live in the same database cluster as your primary connection. For example, a Postgres application using all three Solid components might have the following configuration: ```yaml theme={null} default: &default adapter: postgresql pool: <%= ENV.fetch("RAILS_MAX_THREADS", 3) %> production: primary: <<: *default database: my_app_production cache: <<: *default database: my_app_production_cache migrations_paths: db/cache_migrate queue: <<: *default database: my_app_production_queue migrations_paths: db/queue_migrate cable: <<: *default database: my_app_production_cable migrations_paths: db/cable_migrate ``` You only need to keep the connections your application actually uses. If you are using MySQL, use the `mysql2` adapter and its gem instead. Cloud provides a connection URL for each connection, and Rails reads them automatically: | Connection | Environment variable | | - | - | | `primary` | `DATABASE_URL` | | `cache` | `CACHE_DATABASE_URL` | | `queue` | `QUEUE_DATABASE_URL` | | `cable` | `CABLE_DATABASE_URL` | To have Cloud provision these databases, keep the conventional connection names and leave out any `url:` entries. It skips connections that have an explicit URL or `replica: true`, and you will need to configure connections with any other name yourself. Since Cloud reads the structure of your YAML file without evaluating its Ruby expressions, make sure your production connection definitions are written out in the file. You may override the injected secondary URLs using your own environment variables or linked secrets, but those external connections are then yours to manage. When you replicate an environment, Cloud copies or creates the attached secondary databases based on the database replication option you choose. If you have set custom URLs, review them before deploying a replica or preview environment so it doesn't accidentally use your production data. Changing `config/database.yml` on its own doesn't update an existing environment's database attachments, so be sure to declare your connections before Cloud scans your repository and you attach the database. Detaching a database removes the environment's secondary connections, but the databases themselves are kept. Cloud waits for your attached databases to become available before deploying. Keep in mind that creating these connections doesn't install the Solid gems or start a queue worker for you. You will still need to configure each Solid component to use its corresponding Rails connection and include its migration or schema files. The [Rails multiple database guide](https://guides.rubyonrails.org/active_record_multiple_databases.html) walks through the application configuration. ### Prepare the databases Database preparation belongs in your environment's [deploy commands](/docs/environments#deploy-commands): ```sh theme={null} bin/rails db:prepare ``` Cloud runs this command just before your new deployment starts receiving traffic, and it cancels the rollout if the command fails. Rails prepares each of your configured databases and applies any pending migrations. New Rails environments start with this command commented out. When you attach a database, Cloud enables it for you automatically, as long as you haven't customized your deploy command. If you have, simply add the preparation step yourself. You should avoid running migrations from your start command. The start command runs every time an instance starts, including during deployments, autoscaling, and wake-ups after scaling to zero. Since your previous deployment keeps running while the new one rolls out, you should also write your migrations so they remain compatible with both. ## Build and serve assets When Cloud detects Propshaft or Sprockets in a Rails application that isn't configured as API-only, it pre-fills the following build command: ```sh theme={null} SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile ``` If Cloud also detects a JavaScript package manager, it adds a step to install your JavaScript dependencies. Ruby runtimes include Node.js, npm, and Yarn. Be sure to keep the dependencies your asset build needs, including any development dependencies used by your JavaScript build tools. If you use a custom asset pipeline, review the pre-filled command and adjust it as needed. API-only Rails applications don't receive this default asset build. Cloud's Nginx server serves files from your application's `public` directory, including the compiled assets in `public/assets`. The `SECRET_KEY_BASE_DUMMY=1` setting only applies to asset compilation. Your real `SECRET_KEY_BASE` is still used at runtime, so don't add the dummy setting as an environment variable. Also, keep in mind that initializers that access your credentials or database may still require those resources while your assets compile. ## Caches and background jobs When you attach a [Laravel Valkey](/docs/resources/caches/valkey) or [Redis](/docs/resources/caches/redis) cache, Cloud provides a `REDIS_URL` variable. You should configure your cache library or Rails cache store to use this URL, and make sure it supports TLS when the URL uses the `rediss://` scheme. To use Rails' Redis cache store, include the `redis` gem and add the following to your `config/environments/production.rb` file: ```ruby theme={null} config.cache_store = :redis_cache_store, { url: ENV.fetch("REDIS_URL") } ``` If your application uses Solid Cache, you may keep your existing database cache configuration instead. Either way, choose the backing store your application is configured to use. You may run your background jobs as [custom background processes](/docs/workers#custom-background-processes) on your App cluster or a worker cluster. Set the command for the job backend you are using: | Backend | Example command | | - | - | | Solid Queue | `bundle exec bin/jobs` | | Sidekiq | `bundle exec sidekiq` | | GoodJob | `bundle exec good_job start` | Be sure to keep the required gems and binstubs in your production bundle. Cloud suggests Sidekiq and GoodJob commands based on your lockfile, along with any processes from your Procfile. If you are using Solid Queue with `bin/jobs`, add the process yourself. You should run your workers as separate background processes rather than enabling `SOLID_QUEUE_IN_PUMA` on your web server. Each background process runs on every replica of its cluster, so account for your total worker concurrency and database connections when choosing process counts and replica limits. If your workers need to process jobs or recurring tasks while your App cluster [scales to zero](/docs/workers#workers-and-scale-to-zero), keep their worker cluster awake. Solid Queue can run recurring tasks using its own scheduler and `config/recurring.yml` file. To use it, configure your recurring tasks in your application and run the jobs process. Cloud's scheduler controls for Laravel and Symfony don't configure Rails recurring tasks. ## Store files in object storage For user uploads, you should use [object storage](/docs/resources/object-storage). To get started, attach a private bucket as your environment's default disk. Cloud provides the bucket's AWS connection variables, but you will need to select and configure an Active Storage service in Rails yourself. First, add the `aws-sdk-s3` gem to your production `Gemfile`, run `bundle install` locally, and commit the updated lockfile. Then, add the following service to your `config/storage.yml` file: ```yaml theme={null} cloud: service: S3 access_key_id: <%= ENV.fetch("AWS_ACCESS_KEY_ID") %> secret_access_key: <%= ENV.fetch("AWS_SECRET_ACCESS_KEY") %> region: <%= ENV.fetch("AWS_REGION", "auto") %> bucket: <%= ENV.fetch("AWS_BUCKET") %> endpoint: <%= ENV.fetch("AWS_ENDPOINT_URL") %> force_path_style: false ``` Finally, select the service in your `config/environments/production.rb` file: ```ruby theme={null} config.active_storage.service = :cloud ``` With this configuration, your uploads live outside of your instance's filesystem, and Rails uses signed URLs to provide access to them. Be sure to keep the service private and leave out any per-object ACL options. Cloud's object storage manages visibility at the bucket level, so it rejects the ACL requests Active Storage sends when a service uses `public: true`. The Ruby runtime includes libvips for image variants. If your application transforms images, include the `image_processing` gem as well. The [Active Storage guide](https://guides.rubyonrails.org/active_storage_overview.html) covers direct uploads and variant configuration in more detail. ## Configure Puma concurrency You should configure Puma's process and thread counts based on your instance's CPU and memory. Unlike Python applications, Cloud doesn't calculate `WEB_CONCURRENCY` for Ruby applications. You may set it yourself, or start with Puma's single-process mode and increase concurrency once you have a feel for your application's memory usage. For example, you might add the following settings to your existing `config/puma.rb` file: ```ruby theme={null} thread_count = Integer(ENV.fetch("RAILS_MAX_THREADS", "3")) threads thread_count, thread_count workers Integer(ENV.fetch("WEB_CONCURRENCY", "0")) force_shutdown_after 20 worker_shutdown_timeout 25 ``` Setting `WEB_CONCURRENCY=0` runs a single server process without clustered workers. Keep in mind that each clustered worker has its own thread pool and its own database connection pools, so set the pool for each database large enough to accommodate every thread that uses it, including any background or asynchronous work. ## Shut down gracefully When an instance stops, whether during a deployment or while scaling down, Cloud sends a `SIGTERM` signal to your application's process. Puma handles this signal gracefully by letting active requests finish before exiting. You should keep Puma's shutdown limits, such as the `force_shutdown_after` and `worker_shutdown_timeout` settings in the previous example, shorter than your environment's **graceful shutdown timeout**. This leaves time for the proxy and the rest of the instance to stop cleanly. If your requests or jobs need more time to finish, increase the environment's timeout as well. Puma's [configuration documentation](https://puma.io/puma/Puma/DSL.html) describes the available shutdown and concurrency options. ## Running behind the proxy Cloud handles TLS for you before forwarding requests to your application, so Puma only needs to speak plain HTTP. Along the way, its proxy passes along the original request scheme in the `X-Forwarded-Proto` header, which allows Rails to recognize HTTPS requests. You should keep your production HTTPS configuration, such as `config.force_ssl = true`, in place. If you restrict hosts using `config.hosts`, be sure to allow your Cloud domain and any custom domains. You should also configure the hostnames used in URLs generated outside of a request, such as links in your mailers. Cloud provides an `APP_URL` variable, but Rails doesn't apply it to these settings automatically. ## Logging Cloud captures everything your application writes to stdout and stderr and displays it in the [Logs](/docs/logs) dashboard. Recent Rails applications already log to stdout. If you are deploying an older application that only writes to a log file, configure its logger in your `config/environments/production.rb` file: ```ruby theme={null} config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout)) ``` Keep in mind that the injected `RAILS_LOG_TO_STDOUT` variable only has an effect when your application's configuration reads it. The [Rails configuration guide](https://guides.rubyonrails.org/configuring.html) is a helpful reference when adapting an older application. ## Other Ruby and Rack applications For Ruby applications that don't use Rails, Cloud uses the `web` command from your Procfile if you have one. Otherwise, it uses the Ruby or Rack entrypoint you selected. A Ruby file such as `app.rb` runs with `bundle exec ruby app.rb`, so your program needs to start its own server, read `PORT`, and accept IPv6 connections. For a Rack entrypoint such as `config.ru`, Cloud pre-fills the following start command: ```sh theme={null} bundle exec rack-start.rb config.ru ``` Cloud's launcher uses Puma when it is available in your production bundle, or a compatible `rackup` executable otherwise, and it binds the server to `::` on `PORT` for you. Be sure to add Puma, or Rackup with a compatible server, to your production dependencies. Generic Ruby applications receive `RACK_ENV=production`, `BUNDLE_WITHOUT=development:test`, and the connection variables for any attached resources. Their `DATABASE_URL` uses the `mysql://` or `postgresql://` scheme, so you may need to adapt it for the database library you use. The Rails-specific asset builds, secrets, and database preparation described in this guide don't apply to generic Ruby applications. # Deployments Source: https://cloud.laravel.com/docs/deployments Learn how deployments work in Laravel Cloud, including builds, push to deploy, deploy hooks, and zero-downtime releases. ## Introduction Deployments in Laravel Cloud happen whenever you have new code to release, new resources to attach, or environment settings that you want to update. When a new deployment is triggered, Laravel Cloud will take your code and environment settings, build an image configured for your application's runtime and version, and then run your build and deploy commands. Once your build completes successfully, the existing deployment will be gracefully terminated (allowing any running processes to complete) and the new deployment will be brought online with zero downtime. ## Deploy options ### Push to deploy Every time you push new code to your remote Git branch, a new deploy is automatically triggered. Push to deploy is enabled by default on all environments. To change this setting, go to **Settings > Deployments**. ### Deploy hooks If you prefer to trigger a deployment via an HTTP endpoint, you can enable the "Deploy hook" option in **Settings > Deployments**. When enabled, you will be provided a URL that you can make a POST request to as part of your CI/CD flow. You can refresh your URL anytime from the Deployments settings. You can also deploy a specific commit by passing a `commit_hash` query parameter to the deploy hook URL. The commit hash should belong to the branch configured for the environment. ```shell theme={null} curl -X POST "https://your-deploy-hook-url?commit_hash=abc123def456" ``` If no commit hash is provided, the latest commit from the environment's branch will be deployed. #### Example using GitHub Actions Deploy hooks are perfect for integrating Laravel Cloud with your CI / CD pipeline. Here's a complete example using GitHub Actions: 1. First, add your deploy hook URL as a secret in your GitHub repository: * Go to your GitHub repository settings * Navigate to Secrets and variables → Actions * Add a new secret named `LARAVEL_CLOUD_DEPLOY_HOOK` with your deploy hook URL 2. Create a `.github/workflows/deploy.yml` file in your repository: ```yaml theme={null} name: Deploy to Laravel Cloud on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy to Laravel Cloud run: | curl -X POST "${{ secrets.LARAVEL_CLOUD_DEPLOY_HOOK }}?commit_hash=${{ github.sha }}" ``` 3. Commit and push the workflow file to trigger your first deployment. Unlike traditional deployment processes that require installing dependencies and running build commands in CI, Laravel Cloud handles all of this for you. The deploy hook triggers Laravel Cloud to: * Pull your code from the specified commit * Run your configured build commands * Run your configured deploy commands * Deploy your application with zero downtime ### Manual You can trigger a deployment from the Laravel Cloud dashboard anytime by clicking the "Deploy" button from the Environment overview page or Deployments page. After updating environment settings, your changes are staged until you deploy them. Review everything that is pending and deploy the batch from the staged changes banner, or use the "Deploy" button at any time. ## Troubleshooting ### Framework or runtime version not supported Laravel Cloud requires Laravel 9 or greater. In addition, you should be using the latest minor version of the `laravel/framework` Composer package. The minimum minor versions required are: * Laravel 11: `v11.41.3` * Laravel 10: `v10.48.28` * Laravel 9: `v9.52.20` Watch [this video](https://youtu.be/95iC9L-3CxY) to learn more about fixing this framework error. If you receive an error during a deployment that *"The \[laravel/framework] package was found in the \[composer.lock] file, but the version is not supported. Upgrade Laravel to the latest minor version"* then you can update by running the following command: ```shell theme={null} composer update laravel/framework ``` Laravel Cloud requires Symfony 7.4 LTS or 8.x. Ensure your `composer.json` specifies a compatible version and that your `composer.lock` is up to date: ```shell theme={null} composer update symfony/framework-bundle ``` Next.js applications can run on any [supported Node.js, Bun, or Deno version](/docs/runtimes#node-js-bun-and-deno). If you're using Node.js, ensure your `package.json` specifies a compatible engine: ```json theme={null} { "engines": { "node": ">=20" } } ``` Bun and Deno run on a fixed version, so no `engines` configuration is needed for those runtimes. Nuxt applications can run on any [supported Node.js, Bun, or Deno version](/docs/runtimes#node-js-bun-and-deno). If you're using Node.js, ensure your `package.json` specifies a compatible engine: ```json theme={null} { "engines": { "node": ">=20" } } ``` Bun and Deno run on a fixed version, so no `engines` configuration is needed for those runtimes. JavaScript applications, including Express and Hono, can run on any [supported Node.js, Bun, or Deno version](/docs/runtimes#node-js-bun-and-deno). If you're using Node.js, ensure your `package.json` specifies a compatible engine: ```json theme={null} { "engines": { "node": ">=20" } } ``` Bun and Deno run on a fixed version, so no `engines` configuration is needed for those runtimes. Laravel Cloud reads the `go` directive in your `go.mod` file and uses the lowest supported version that satisfies it. If no supported version satisfies the directive, the deployment fails before building. Update the `go` directive to a version listed in [Runtimes](/docs/runtimes#go): ```text theme={null} go 1.25 ``` Laravel Cloud reads your Python version from a `.python-version` file or, when that file does not declare a version, the `requires-python` constraint in `pyproject.toml`. If the pinned version is unsupported, or no supported version satisfies the constraint, the deployment fails before building. Update your declaration to a version listed in [Runtimes](/docs/runtimes#python): ```toml theme={null} [project] requires-python = ">=3.12" ``` A version declared in your repository takes precedence over the version selected in your environment settings. ### Deployment succeeds but serves no traffic Laravel Cloud's proxy, which runs alongside your application in each instance, routes traffic to your application on the port set by the `PORT` environment variable (`3000` by default, or the port you chose when creating the application). Ensure that your Express, Hono, or other JavaScript application reads `PORT` rather than listening on a hardcoded port. Laravel Cloud's proxy, which runs alongside your application in each instance, routes traffic to your application on the port set by the `PORT` environment variable (`3000` by default, or the port you chose when creating the application). The default start command, `next start`, reads `PORT` automatically, so this works out of the box for most applications. If you've overridden the start command with a custom server (for example, a `server.js` file using Express), the build can succeed even if that server listens on a different, hardcoded port. Laravel Cloud has no way to detect this, so the deployment goes live without routing any traffic to your application. Make sure your custom server reads the `PORT` environment variable rather than hardcoding a port number. Laravel Cloud starts Nuxt applications with Nitro's default `node-server` preset (`.output/server/index.mjs`). If your `nuxt.config` still sets a host-specific `nitro.preset` (for example, `vercel`, `netlify`, or `cloudflare`) left over from a previous provider, or a `NITRO_PRESET` environment variable is set, Nitro builds output for that host instead (such as `.vercel/output`). The build completes without error, but Laravel Cloud has no way to serve that output, so the deployment goes live without routing any traffic to your application. Remove the `nitro.preset` option and any `NITRO_PRESET` environment variable so Nitro can auto-detect the `node-server` preset. Laravel Cloud's proxy, which runs alongside your application in each instance, routes traffic to your application on the port set by the `PORT` environment variable (`3000` by default). If your application binds to a hardcoded port instead of reading `PORT`, the build and deployment can both succeed, but the deployment goes live without routing any traffic to your application. Make sure your application reads the `PORT` environment variable rather than hardcoding a port number. Laravel Cloud's proxy, which runs alongside your application in each instance, routes traffic to your application on the port set by the `PORT` environment variable (`3000` by default). The default start commands for Django, FastAPI, and Flask all read `$PORT`, so this works out of the box unless you've overridden the start command with something that hardcodes a port. Make sure your start command reads the `PORT` environment variable rather than hardcoding a port number. ### Build or start command not configured Go applications require an explicit build command, since Laravel Cloud has no default way to compile a Go module on your behalf. Go, Python, and JavaScript applications require an explicit start command, since Laravel Cloud has no framework-provided way to run them. Laravel Cloud pre-fills a sensible default for each of these when it first detects your application, so this typically only surfaces if you've since cleared the field. If a required command is blank, the deployment fails immediately with *"The environment has no build command configured"* or *"The environment has no start command configured."* For a Go application, restore a build command such as: ```shell theme={null} CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o app . ``` ### Django start command still has the `` placeholder Laravel Cloud discovers your Django project's WSGI module from your repository and pre-fills the start command with it. When the module can't be discovered, the start command falls back to a `` placeholder: ```shell theme={null} gunicorn .wsgi --bind [::]:$PORT ``` Replace `` with your Django project's settings module name (the directory containing `wsgi.py`) before deploying. If the placeholder is still there when you deploy, the deployment fails with *"The start command still contains the `` placeholder. Replace `` with your Django project's module name."* # Domains Source: https://cloud.laravel.com/docs/domains Configure Laravel Cloud domains, connect custom domains, set up DNS, and troubleshoot verification. Laravel Cloud provides two types of domains for each environment: an automatically assigned `laravel.cloud` domain and any custom domains you connect. Domain stuck verifying? Read our docs on [verifying domains](/docs/knowledge-base/domain-verification). ## Cloud domains Each environment is assigned a free `laravel.cloud` domain after its first successful deployment. This is ideal for testing and staging before switching to your own domain. Cloud domains are constructed from your application and environment name. If you rename either, the Cloud domain will change and you will need to redeploy for the change to take effect. Since Cloud domains are frequently used for non-production environments, an `X-Robots-Tag: noindex, nofollow` header is automatically set on all `*.laravel.cloud` domains so they are not indexed by search engines. This header is not set for custom domains. ## Custom domains A custom domain lets visitors reach your application at your own address (e.g., `example.com`) instead of the default `laravel.cloud` domain. Laravel Cloud automatically provisions and renews SSL certificates for each custom domain so your site is served over HTTPS. ### Add a custom domain In the dashboard, open your environment's Network settings and select "Add domain". You'll be asked to choose: * **Wildcard support**: Whether to accept traffic on all subdomains (for example, `*.example.com`). * **Redirect behavior**: Whether Cloud should redirect `www.example.com` to `example.com` (or the reverse). * **Downtime preference**: Whether brief downtime is acceptable during setup, or whether you need an uninterrupted transition with no gaps in service. * **Cloudflare DNS settings**: Whether your DNS is managed by Cloudflare and whether the hostname is already proxied (routed through Cloudflare's network). These choices determine which DNS records Laravel Cloud will ask you to add and in what order. Enter the domain and choose your options. If you selected the uninterrupted path or enabled wildcard support, add the ownership and SSL validation records first. These records let Laravel Cloud confirm you own the domain and issue an SSL certificate before any traffic is switched over. This option is only available if the hostname is not already proxied through Cloudflare's network. Add the origin record(s) shown in the UI. Origin records are the DNS entries that direct your domain's traffic to Laravel Cloud's servers. Use the Refresh action in the dashboard until the domain status shows as connected. Most domains connect within 15 minutes, but DNS propagation can occasionally take longer. ### Verification paths Laravel Cloud supports two verification approaches. The right choice depends on whether you can tolerate a brief gap in service while DNS changes take effect: * **Real-time verification (flexible)**: Point the domain to Laravel Cloud first, then Laravel Cloud will verify ownership and issue an SSL certificate. This is the simplest path, but there may be a short window where the domain is not yet serving over HTTPS. * **Pre-verification (uninterrupted)**: Prove ownership and issue the SSL certificate before switching traffic. This avoids any downtime or insecure window, but requires additional DNS records up front. Required for wildcard domains. This approach is only available if the hostname is not already proxied through Cloudflare's network. ## DNS records you will see in Cloud When you open a domain's configuration, Laravel Cloud will show the exact DNS records required for your setup. Copy each record's type, name, and value exactly as shown into your DNS provider. ### Origin records Origin records are the primary DNS entries that tell the internet to send traffic for your domain to Laravel Cloud: * An **A** record maps your domain to an IP address and is common when you are not using Cloudflare DNS. * A **CNAME** record maps your domain to another hostname and is common when you are using Cloudflare DNS (Cloudflare supports CNAME flattening at the apex, which allows a CNAME on the root domain). ### Ownership verification record During pre-verification, Laravel Cloud may require a temporary TXT record to confirm that you control the domain. This record looks like: `TXT _cf-custom-hostname. -> ` Once ownership is confirmed, this record is no longer needed, though leaving it in place will not cause any issues. ### SSL validation records To issue an SSL certificate for your domain (so it can be served over HTTPS), Laravel Cloud may require one or more validation records: `TXT _acme-challenge. -> ` `CNAME _acme-challenge. -> ` (common for wildcard / DCV delegation) If you are using wildcard support, keep the DCV delegation CNAME record in place permanently. This record allows Laravel Cloud to automatically renew your wildcard SSL certificate — removing it will prevent future renewals. ## Understanding verification status A domain is fully connected once three components are verified: * **Hostname**: Ownership of the domain is confirmed. * **SSL**: An SSL certificate has been issued and is active, enabling HTTPS. * **Origin**: DNS is correctly routing traffic to Laravel Cloud. As verification progresses, the dashboard will show one of the following statuses: * **Verifying ownership**: Laravel Cloud is waiting for your ownership and SSL validation DNS records to become visible. This is the propagation stage. * **Verifying**: Ownership and SSL are confirmed, but origin routing has not been detected yet. Your origin DNS record may still be propagating. * **Connected**: All three components are verified and your domain is live. * **Timed out**: Verification did not complete within the allowed window. Review your DNS records for errors and retry. Laravel Cloud retries verification checks for approximately 12 hours before timing out, so there is no need to manually re-trigger during this period. If you are using real-time verification, visiting your domain in a browser can help Laravel Cloud detect traffic flowing through the network and speed up the final verification step. ## Wildcard domains A wildcard domain (e.g., `*.example.com`) allows any subdomain — such as `app.example.com`, `api.example.com`, etc. — to route to your environment without configuring each one individually. Wildcard domains require pre-verification unless the hostname is already being proxied through Cloudflare's network. When configuring a wildcard domain: * Also configure the root domain `example.com`, so both `example.com` and its subdomains are covered. * Add the DCV delegation record shown in the UI. This record allows Laravel Cloud to continue issuing and renewing wildcard SSL certificates on your behalf. If your DNS is managed by Cloudflare, ensure DCV delegation records under `_acme-challenge` are configured as **DNS only** (gray cloud, not proxied). Proxying these records will block certificate issuance. ## Managing domains From your environment's domain settings, you can detach and reassign domains between environments in the same organization. You can also set a verified root domain as the primary domain for an environment. Primary domains cannot be moved or removed until they are unset as the primary domain. ## Limitations There are no limitations on the number of Cloud environments that can have a custom domain assigned to them. Each plan includes a number of custom domains across your entire organization: * **Starter**: 10 custom domains per organization * **Growth**: 50 custom domains per organization * **Business**: 250 custom domains per organization * **Enterprise**: Custom Additional custom domains beyond your plan's included amount are billed at \$0.25 per domain per month. If you have a special use case that requires many domains (for example, multi-tenant applications), please [contact us](/docs/support) to discuss raising your limits. ## Troubleshooting For guided troubleshooting and provider-specific DNS instructions, see the [Domain Verification](/docs/knowledge-base/domain-verification) guide. ### Verify DNS from the terminal You can confirm your records are publicly visible by running the following commands in your terminal. Replace `example.com` with your actual domain. Both `dig` and `nslookup` are shown — use whichever is available on your system: ```bash theme={null} # Which DNS provider is responsible for your domain? dig NS example.com +short nslookup -type=NS example.com # Are your origin records resolving? (use the record type you configured — A or CNAME) dig A example.com +short dig CNAME example.com +short nslookup -type=A example.com nslookup -type=CNAME example.com # Is the ownership verification record visible? dig TXT _cf-custom-hostname.example.com +short nslookup -type=TXT _cf-custom-hostname.example.com # Are the SSL validation records visible? (may be TXT or CNAME depending on your setup) dig TXT _acme-challenge.example.com +short dig CNAME _acme-challenge.example.com +short nslookup -type=TXT _acme-challenge.example.com nslookup -type=CNAME _acme-challenge.example.com ``` If a command returns no output, the record is either missing or has not finished propagating. # Environments Source: https://cloud.laravel.com/docs/environments Manage Laravel Cloud environments, deployment settings, variables, domains, commands, and runtime configuration. ## Introduction Laravel Cloud applications can be made up of many environments, such as "production", "staging", or even short-lived environments used for trialing new features you're developing for your application. Compute infrastructure, resources, and deployment settings are unique to each environment, allowing you to fine-tune each environment based on its purpose. For example, you might wish to assign small Flex compute instances that scale to zero to your staging environment, while larger, always-on compute instances are assigned to your production environment. ## Build and deploy commands You may define how your application is built during deployment from the **Deployments** section of your environment settings. ### Build commands Build commands allow you to customize the build process for your application during deployment. Typically, your Laravel build command will install your Composer and npm dependencies and compile your application's assets: ```shell theme={null} composer install --no-dev && npm run build ``` Running `php artisan optimize` or `php artisan config:cache` should be done during the build process, not during the deploy process. #### Private Composer packages To allow the installation of private Composer packages, you will need to configure your application's Composer HTTP authentication credentials for each package using the `composer config` command. You should add this command to your build commands prior to invoking `composer install`: ```shell theme={null} composer config http-basic.composer.fluxui.dev your-username your-license-key composer install --no-dev ``` Typically, your Symfony build command will install Composer dependencies and compile your application's assets: ```shell theme={null} composer install --no-dev && php bin/console asset-map:compile ``` #### Private Composer packages To allow the installation of private Composer packages, you will need to configure your application's Composer HTTP authentication credentials for each package using the `composer config` command. You should add this command to your build commands prior to invoking `composer install`: ```shell theme={null} composer config http-basic.example.com your-username your-license-key composer install --no-dev ``` Typically, your Next.js build command will install Node dependencies and compile your application: ```shell theme={null} npm ci && npm run build ``` Typically, your Nuxt build command will install Node dependencies and compile your application: ```shell theme={null} npm ci && npm run build ``` Typically, your Node.js build command will install dependencies and compile your application: ```shell theme={null} npm ci && npm run build ``` Laravel Cloud pre-fills your Go build command for the detected entrypoint. An application with its `main` package at the repository root and no detected cgo requirements uses: ```shell theme={null} CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o app . ``` Cloud adjusts the package path for entrypoints such as `cmd/server` and sets `CGO_ENABLED=1` when it detects cgo requirements. The default start command, `./app`, runs the resulting binary. If you change the output path or binary name, update the start command to match. Laravel Cloud installs Python dependencies automatically, using `uv.lock`, `poetry.lock`, `Pipfile.lock`, `requirements.txt`, or `pyproject.toml`, in that order. Lockfile tools export dependencies for pip to install into the shared Python user directory. Cloud pre-fills additional build steps when needed. Django projects with a `STATIC_ROOT` setting or WhiteNoise dependency receive `python manage.py collectstatic --noinput`. Projects missing a compatible application server receive `pip install --user gunicorn` for WSGI or `pip install --user uvicorn` for ASGI. You may edit or remove these commands to suit your project. See the [Python deploy guide](/docs/deploy-guides/python) for server and static-file configuration. Laravel Cloud installs gems automatically using `Gemfile.lock`. Rails applications with detected assets receive an asset compilation command, preceded by JavaScript dependency installation when needed: ```shell theme={null} SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile ``` Review your asset pipeline and any additional build steps in the [Ruby and Rails deploy guide](/docs/deploy-guides/ruby#build-and-serve-assets). Generic Ruby and API-only Rails applications do not receive this default asset build. Build commands must complete within 15 minutes or they will time out. #### Dynamic environment variables For Laravel and Symfony applications, Laravel Cloud writes your environment's variables to a `.env` file in the build context. You may append a derived value for your application to read: ```shell theme={null} # Adding a dynamic environment variable echo "MY_DYNAMIC_VAR=value" >> .env ``` JavaScript, Go, Python, and Ruby applications receive variables through the process environment during builds and at runtime. Appending to a `.env` file does not configure their runtime variables. Add persistent values under your environment's [environment variables](#environment-variables) instead. ### Deploy commands Your environment's "Deploy Commands" are run on your Laravel Cloud infrastructure just before a new deployment goes "live". Typically, these commands will be used to migrate your environment's database. Unlike build commands, changes made to the filesystem by deploy commands will not be persisted to your application. Deploy commands must complete within 15 minutes or they will time out. For Rails applications using a database, run `bin/rails db:prepare` as a deploy command. Attaching a database enables the initially commented command if you have kept the default deploy command. See [Rails database preparation](/docs/deploy-guides/ruby#prepare-the-databases). #### Unnecessary build and deploy commands This section applies to Laravel applications. The following commands are either automatically handled by Laravel Cloud or should not be run during deployment: * **`php artisan queue:restart`** - Queue workers are automatically restarted after each deployment * **`php artisan horizon:terminate`** - Horizon processes are automatically managed during deployments * **`php artisan optimize:clear`** - This clears the cache and can cause unexpected behavior, especially related to the queue * **`php artisan storage:link`** - The symbolic link won't persist as changes made during deploy commands are not saved. Use [Laravel Object Storage](/docs/resources/object-storage) for persistent file storage instead. Typically, your deploy commands should only include database migrations and other essential post-deployment tasks. ## Environment settings ### Environment variables Within your environment's settings, the environment variables section allows you to customize the variables available to your environment. In addition to injecting your custom environment variables, Laravel Cloud will automatically inject a variety of environment variables into your environment on your behalf, including any credentials necessary to connect to Laravel Cloud resources like databases, key-value storage, or object storage. For sensitive values that should be shared across multiple environments, use [Secrets Manager](/docs/secrets) to create encrypted organization-level secrets and link them to the environments that need them. Custom environment variables take priority and will override any automatically injected environment variables. After you change an environment's variables, redeploy the environment for the changes to take effect. #### How variables reach your application Laravel Cloud delivers your environment's variables differently depending on the runtime: Laravel Cloud writes your variables to a `.env` file in your application's root directory before your application starts, so the framework reads them the same way it does locally. Laravel Cloud sets your variables on the application process, the way `export` does in a shell. Read them from `process.env`. Laravel Cloud sets your variables on the application process, the way `export` does in a shell. Read them with `os.Getenv`. No `.env` file is written at runtime, so your application does not need a loader such as `godotenv`. Laravel Cloud sets your variables on the application process, the way `export` does in a shell. Read them from `os.environ` — or, in a Django application, through your settings module as usual. No `.env` file is written at runtime, so your application does not need a loader such as `python-dotenv`. Laravel Cloud sets variables on your application process. Read them from `ENV`. Rails reads `DATABASE_URL` automatically, while custom application settings require you to read the corresponding variables in your configuration. Laravel Cloud also makes your environment's variables available during builds. Laravel and Symfony builds include a `.env` file for the framework to read. JavaScript, Go, Python, and Ruby build commands receive exported process variables. ### HTTP basic authentication HTTP basic authentication allows you to protect an environment with a username and password before traffic reaches your application. This is useful for staging environments, private demos, preview environments, or sleeping environments that should not wake up because of unauthorized requests or automated bot traffic. You may enable HTTP basic authentication from your environment's General Settings page in the Security section. When enabled, users can access the environment using the username `admin` and the password you set. Passwords must be between 5 and 32 characters and cannot contain the `:` character. HTTP basic authentication is available on the [Growth plan](/docs/pricing) or higher. After enabling, disabling, or changing the password, a re-deployment is required in order for the changes to take effect. ### Runtime #### PHP runtime You may select the PHP version that should be used by an environment on the environment's General Settings page. After changing the PHP version, a re-deployment is required in order for the changes to take effect. See [Runtimes](/docs/runtimes#php) for the supported PHP versions. #### Node.js, Bun, and Deno runtimes Next.js, Nuxt, TanStack Start, Express, and Hono applications run on the Node.js, Bun, or Deno runtime, detected automatically from the configuration files in your repository. See [Runtimes](/docs/runtimes#node-js-bun-and-deno) for detection rules and supported versions. The Node.js version is selectable on the environment's General Settings page; after changing it, a re-deployment is required for the change to take effect. Bun and Deno applications run on a fixed version and don't offer version selection in the dashboard. #### Go and Python runtimes Go and Python applications are detected automatically from your repository: a `go.mod` file for Go, or a `pyproject.toml`, `requirements.txt`, `Pipfile`, or `setup.py` file for Python. Rather than a dashboard setting, Laravel Cloud reads the language version straight from your repository (the `go` directive in `go.mod` for Go; a `.python-version` file or the `requires-python` constraint in `pyproject.toml` for Python). See [Runtimes](/docs/runtimes) for supported versions and what happens when a detected version isn't one Laravel Cloud publishes. #### Ruby runtime Laravel Cloud reads Ruby version declarations from your deployment's commit. When the repository does not declare a version, you may select one in **General Settings**. See [Ruby versions](/docs/runtimes#ruby) for the supported release lines and declaration order. ### PHP extensions PHP extensions are only available for PHP runtime environments (Laravel and Symfony). Laravel Cloud currently supports the following PHP extensions: ``` apcu, bcmath, calendar, Core, ctype, curl, date, dom, ev, excimer, exif, fileinfo, filter, ftp, gd, gettext, gmp, grpc, hash, iconv, igbinary, imagick, imap, intl, json, ldap, libxml, mbstring, mongodb, msgpack, mysqli, mysqlnd, openssl, pcntl, pcre, PDO, pdo_mysql, pdo_pgsql, pdo_sqlite, pdo_sqlsrv, Phar, posix, pspell, random, readline, redis, Reflection, session, shmop, SimpleXML, soap, sockets, sodium, SPL, sqlite3, sqlsrv, standard, tokenizer, xml, xmlreader, xmlwriter, xsl, Zend OPcache, zip, zlib. ``` You can also list the currently loaded extensions by running `php -m` using Laravel Cloud's "Command" feature in your environment dashboard. ### PHP memory limit This section applies to PHP runtime environments (Laravel and Symfony). Laravel Cloud allocates PHP memory dynamically based on a percentage of your instance's total memory. If your application requires a specific amount, you can override this by defining a new `memory_limit`. You can override the default memory limit by adding configuration directly in your application code. The most common method is to update your `public/index.php` and your `artisan` file: ```php theme={null} ## Custom domains Of course, before shipping your application to the world, you will likely want to assign your own custom domain name to your production environment. Laravel Cloud will guide you through DNS configuration, verify domain ownership, and issue an SSL certificate automatically. For comprehensive documentation (DNS records, verification paths, wildcards, provider-specific guides, and plan limits), see [Domains](/docs/domains). If your domain verification is taking longer than expected, check out our docs on [verifying domains](/docs/knowledge-base/domain-verification). ## Stop and restart To stop an environment, click the "..." button next to the environment's "Deploy" button. Then, click "Stop". When you stop an environment, all App and Worker clusters within the environment will be shutdown. This means all web traffic, background processes, and scheduled tasks will stop processing. You will not be charged for the environment's compute, but you will still be charged for any attached resources. You can restart the environment using the same dropdown menu. A full deployment is required to restart an environment. ## Replicate It is common for environments in the same application to have similar or identical resource and settings configurations. Therefore, when creating new environments, it is often more convenient to clone an existing environment and make changes rather than creating a new environment from scratch. To replicate an environment, click the "..." button next to the environment's "Deploy" button. Then, click "Replicate". Confirm you are replicating the correct environment and Git branch, then enter a name for your new environment. By default, all General, Environment, and Deployment settings will be duplicated. You can optionally edit the default replication settings for compute and resources. The default replication behavior is: * Compute: duplicate all clusters at a smaller size, with Scale-to-Zero enabled * Database: create a new database cluster that scales to zero, or a new database within the same cluster if your database does not support scale-to-zero replication * Cache: create a new cache that scales to zero, or a new cache at the smallest available size if your cache does not support scale to zero * Object storage: create a new bucket * WebSockets: create a new WebSocket server If you choose to share the cache instead, Cloud adds a `REDIS_PREFIX` environment variable set to `application:environment:` so each environment's keys stay separate. If the environment runs Laravel Horizon, Cloud also sets `HORIZON_PREFIX`. Review and edit the "Replication options" as needed before deploying your new environment. The defaults provided are a sensible balance between cost and performance, but may not be right for your application's specific use case. Use extra care when replicating a production environment to avoid reusing resources in a way that will impact performance or interfere with queued jobs, sessions, or other application data. To generate an isolated environment automatically for every pull request, use [preview environments](/docs/preview-environments) instead. ## Commands Laravel Cloud allows you to execute arbitrary shell commands directly in your environment. Navigate to your environment's **Commands** tab to run one-time commands for any supported framework or runtime. For example, `php artisan cache:clear` in a Laravel application, `php bin/console cache:clear` in a Symfony application, `node script.js` in a Node.js application, `./app migrate` in a Go application, or `python manage.py shell` in a Django application. Commands should be non-interactive and may not run for more than 30 minutes. Commands will be executed on any available instance in your environment. ## Filesystem Environment filesystems are **ephemeral**, meaning files may not persist across requests or jobs. New deployments or re-deployments will reset the filesystem. In addition, each replica of your compute cluster has its own filesystem. Thus, you should treat the filesystem as temporary, unshared disk space that is only consistent during a single request or job. The total disk space available on each replica is proportional to the compute / RAM of the cluster. Every 1GB of RAM is equal to 512MB of disk space. For example, a cluster with 2GB of RAM will have 1GB of ephemeral disk space available to it. If you exceed the available disk space, your application may crash and the deployment may need to restart. For persistent cache and session storage, PHP applications should use the `redis` or `database` drivers via a [cache](./resources/caches) or [database](./resources/databases/laravel-mysql) resource. JavaScript applications should use their framework's equivalent persistent session and cache adapter backed by one of these resources. Go and Python applications should connect directly to a cache or database resource using the injected `REDIS_URL` or `DATABASE_URL` connection string. For persistent file storage, use [Laravel Cloud Object Storage](./resources/object-storage). ## Nightwatch integration Nightwatch integration is currently available for Laravel applications only. Laravel Cloud environments have built-in support for [Laravel Nightwatch](https://nightwatch.laravel.com) monitoring. Nightwatch provides deep insights into your application environment's performance, exceptions, logs, and overall health. Install the Laravel Nightwatch package in your application locally using [Composer](https://packagist.org/packages/laravel/nightwatch): ```bash theme={null} composer require laravel/nightwatch ``` Run composer require laravel/nightwatch on your local machine to update your composer.json and composer.lock files before deploying. Click the Connect Nightwatch button in your environment dashboard. Toggle Enable monitoring to activate Nightwatch for your environment. Enter your Nightwatch token, which you can find in your Nightwatch application settings. Enabling Nightwatch will automatically run the agent across all the App and Worker clusters in the environment. You can [setup Nightwatch manually](/docs/knowledge-base/nightwatch-on-cloud) if you want the agent to run on specific instances. When enabled, Laravel Cloud will automatically inject the following environment variables into your environment: ``` NIGHTWATCH_TOKEN= NIGHTWATCH_REQUEST_SAMPLE_RATE=0.1 LOG_CHANNEL=stack LOG_STACK=laravel-cloud-socket,nightwatch ``` You can override these variables in your environment variable settings if needed. If you have previously [configured Nightwatch manually](/docs/knowledge-base/nightwatch-on-cloud) with a background process, you must remove that process from every cluster before enabling the built-in integration to avoid issues with your environment. # Free trial Source: https://cloud.laravel.com/docs/free-trial Start on the Starter plan with your first 30 days free and $5 in usage credits. ## Introduction New Starter subscriptions get their **first 30 days free**: the \$5 monthly fee is waived and you receive **\$5 in usage credits**. Use them to ship your first application on Laravel Cloud—on us. ## Getting started Sign up at [cloud.laravel.com](https://cloud.laravel.com/sign-up), select the Starter plan, and add your payment details. Your first 30 days free and \$5 in usage credits are applied automatically. Laravel Cloud promotion showing $5 in free usage credits for the Starter plan with a Get started button. Credits are consumed as you provision and run resources. How far they go depends on what you deploy and for how long. Because [Scale-to-Zero](/docs/compute#scale-to-zero) is on by default, your compute and resources stop consuming credits while your application is idle, which makes your trial go further. ## How far does \$5 go? Laravel Cloud compute and many resources can [scale to zero](/docs/compute#scale-to-zero) when your application is idle, which means they stop consuming credits until traffic returns. For many users, that makes the \$5 go surprisingly far. Here are a few realistic examples: | Scenario | What is running | Estimated runtime | | - | - | - | | Weekend tinkerer | Compute + Serverless Postgres, awake about 1 hour per day | About 4 months | | Active side project | Compute + Serverless Postgres, awake about 4 hours per day | About 5 weeks | | Full-stack app with cache | Compute + Serverless Postgres + Valkey | About 3 weeks | | Everything always on | Compute, Serverless Postgres, Valkey, and WebSockets active and always on | About 7 days | These are estimates, not guarantees. Actual usage depends on the resources you provision, how long they stay active, and whether Scale-to-Zero is enabled. ## After your first 30 days If your usage stays under \$5 during your first 30 days, you pay nothing. You are only charged during this period for usage above your \$5 in credits. After your first 30 days, standard Starter billing begins at \$5/mo plus any usage beyond your monthly \$5 in credits. Your app stays online; nothing turns off. [View plans and pricing](/docs/pricing) # Welcome to Laravel Cloud Source: https://cloud.laravel.com/docs/intro The official infrastructure and deployment platform for Laravel, with support for Symfony, Next.js, Nuxt, Go, Python, Rails, and more. Laravel Cloud is a fully managed infrastructure platform for deploying and scaling ambitious web applications, with built-in solutions for web and worker compute, relational databases, key-value storage, managed queues, file and object storage, and more. Laravel Cloud is built for the Laravel framework and a curated selection of additional popular frameworks. We take extra care to support each framework's particular conventions, from how it is built and started to how its environment is configured. When you create an application, Laravel Cloud detects its framework and configures the matching runtime for you: | Framework | Runtime | | - | - | | Laravel | PHP | | Symfony | PHP | | PHP (Other PHP backend applications) | PHP | | Next.js | Node.js, Bun, or Deno | | Nuxt | Node.js, Bun, or Deno | | TanStack Start | Node.js, Bun, or Deno | | Express | Node.js, Bun, or Deno | | Hono | Node.js, Bun, or Deno | | NestJS | Node.js, Bun, or Deno | | Node.js (Other backend Node.js applications) | Node.js, Bun, or Deno | | Go | Go | | Django | Python | | Flask | Python | | FastAPI | Python | | Python (Other Python applications) | Python | | Ruby on Rails | Ruby | | Ruby (Other Ruby applications) | Ruby | See [Runtimes](/docs/runtimes) for the supported versions of each runtime. ## Unmatched developer experience Laravel Cloud is the only fully managed platform-as-a-service (PaaS) obsessively optimized for shipping and scaling your applications. * **No application or server configuration necessary.** Most applications built on supported frameworks can be [deployed to Laravel Cloud](/docs/deployments) without any additional changes to your application's architecture. Additionally, no server management experience is required when deploying to Laravel Cloud. * **Fully managed databases and caches.** You can provision and manage [Laravel MySQL](/docs/resources/databases/laravel-mysql) and [Laravel Serverless Postgres](/docs/resources/databases/postgres) databases directly from the Laravel Cloud dashboard. [Laravel Valkey](/docs/resources/caches/valkey) caches may also be provisioned in seconds. * **Managed queues.** Laravel and Symfony applications can use [fully managed queues](/docs/queues#managed-queues) with dedicated workers that automatically scale based on the work waiting to be processed, including scaling to zero when idle, with a built-in dashboard for retrying failed jobs. * **Workers.** All supported frameworks and runtimes can use [dedicated worker clusters](/docs/workers#worker-clusters) to run custom worker tasks, including queue workers and other long-running background processes. * **Zero downtime deployments and scaling.** Laravel Cloud automatically rolls out [changes to your application](/docs/deployments) without downtime. In addition, [scaling your application's infrastructure](/docs/compute#autoscaling) can be done at any time without interrupting your users. * **Scale-to-Zero.** Laravel Cloud can [put your environment to sleep](/docs/compute#scale-to-zero) when it is idle so you are not charged for compute, then wake it in under 500 milliseconds when a request arrives. Managed queues run on dedicated workers and continue to process jobs while your environment sleeps. For Laravel applications, scheduled tasks also continue to run while the environment sleeps. * **Preview environments.** Automatically provision a [fully isolated environment for every pull request](/docs/preview-environments), then tear it down when the pull request is merged or closed, so your team can review changes in a production-like environment before they ship. * **Automatic TLS and load balancing.** All applications running on Laravel Cloud automatically receive [TLS certificates](/docs/domains), which are also automatically updated. Incoming traffic to your application is also automatically [distributed across your available application replicas](/docs/network#cloud-compute-network). * **Cloud Edge Network.** Laravel Cloud partners with Cloudflare to offer a [globally distributed caching and security network at the edge](/docs/network#cloud-edge-network). This edge network provides DDoS protection and edge asset caching to all applications running on Laravel Cloud. * **Monitoring and logs.** Basic [infrastructure metrics](/docs/compute#compute-metrics), such as CPU and memory usage, are available via the Laravel Cloud dashboard. You may also easily [view and search your application's logs](/docs/logs). ## Next steps We can't wait to see what you ship on Laravel Cloud. When you're ready to dive in, check out our [quickstart documentation](/docs/quickstart). ## Prerequisites Laravel applications require Laravel 9.x or greater, and Symfony applications require Symfony 7.4 LTS or 8.x. Your application must also use a supported runtime version. See [Runtimes](/docs/runtimes) for the supported PHP, Node.js, Bun, Deno, Go, Python, and Ruby versions. # Fix 502 Bad Gateway Or Internal Server Errors Source: https://cloud.laravel.com/docs/knowledge-base/502-error Troubleshoot and fix 502 bad gateway errors in apps running on Laravel Cloud. When trying to access your Laravel Cloud-deployed website, a `502 Gateway Error` means that Cloudflare, which is used in the networking layer of Laravel Cloud, was unable to reach your application. This can happen when the instance serving your application becomes unresponsive. Common issues include: ### Your environment may be under-provisioned Depending on the complexity and functionality of your application, your app may consume more memory than is available in your compute instance. When your application attempts to allocate more memory than is available, the pod in which your application is deployed temporarily crashes and needs to reboot. Small compute instances, such as those with 256MB or 512MB RAM are often common culprits for becoming over-allocated. Common places of high RAM utilization include: * **Unoptimized queries.** Consider using eager loading or chunking when necessary to reduce data stored in memory. * **High number of active jobs.** A large number of jobs, particularly those with large payloads, may consume an excess of memory. * **Too many queue workers.** As each worker consumes memory, requesting many workers may consume more memory than anticipated. * **Excessive logging / debugging.** If your application has `APP_DEBUG=true`, you should expect higher memory usage through more verbose logging. * **Inefficient templates.** Large, deeply nested server-side templates and complex looping constructs can increase memory consumption. *** ### Laravel Horizon may be configured improperly If you are using Laravel Horizon to manage your Redis-backed queues, be mindful of how Horizon spawns workers which can directly impact memory usage in your application. First, ensure that within your Laravel Cloud application, you configure Horizon to run with a single process (`1 process`). This is important as Horizon will automatically spawn workers based on the settings within your application's `config/horizon.php` file. Be mindful of how many workers you have defined in your `config/horizon.php` file via the `maxProcesses` key. When Horizon starts, it will automatically spawn processes based on this value for each supervisor you define. In some cases, too many workers may cause an overallocation of memory. ```php {4} theme={null} 'environments' => [ 'production' => [ 'supervisor-1' => [ 'maxProcesses' => 10, // ... ], ], ], ``` Other considerations: * If no jobs are being processed, ensure your `config/horizon.php` file has a key under `environments` that matches your `APP_ENV` value, or includes an `*` key as a fallback for when no matching environment is found. For more information, refer to the [Horizon documentation](https://laravel.com/docs/horizon#environments). * Upgrade to Laravel Horizon >=`v5.31`. Older version of Horizon can be more aggressive in spawning workers on startup. Keep in mind that even if Horizon starts successfully, your application may still crash if spawning the maximum number of workers causes an overallocation of memory. * Considering moving your Horizon, or `queue:work` workers, onto worker clusters separate from your app cluster. This ensures that your application is still reachable, even if your job queues become stressed. # Fix Production Command Failures Source: https://cloud.laravel.com/docs/knowledge-base/command-failed-prod-app Resolve production command failures in Laravel Cloud when commands prompt for confirmation in non-interactive environments. Some migration operations are destructive, which means they may cause you to lose data. As all Laravel Cloud environments default to `APP_ENV=production`, you may run into issues running migrations in an ad-hoc manner using the **Commands** tab from your environment panel. Since these commands do not support interactivity, the command will fail if it attempts to prompt you for input. This happens most commonly when attempting to run migrations in a production environment. ```shell theme={null} APPLICATION IN PRODUCTION. WARN Command cancelled. ``` If you are comfortable with the risks associated with running migrations in a production environment, pass a flag to bypass the production environment warning. Append the `--force` flag to bypass the production prompt: ```bash theme={null} php artisan migrate --force ``` Related commands which may also require the `--force` flag include: ```bash theme={null} php artisan migrate:fresh --force php artisan migrate:refresh --force php artisan db:seed --force ``` Append the `--no-interaction` flag to bypass the production prompt: ```bash theme={null} php bin/console doctrine:migrations:migrate --no-interaction ``` Related commands which may also require the `--no-interaction` flag include: ```bash theme={null} php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration php bin/console doctrine:schema:update --no-interaction --force ``` ### Customizing your `APP_ENV` If you are working on a non-production environment, you may consider overwriting your `APP_ENV` environment variable in your environment's [Custom Environment Variables](/docs/environments#environment-variables) to better match your environment's purpose. Non-production environments will not trigger the same warnings as described above. ``` APP_ENV=development ``` # Domain Verification Source: https://cloud.laravel.com/docs/knowledge-base/domain-verification Learn how to add, validate, and verify custom domains on Laravel Cloud. When you add a custom domain to Laravel Cloud, Cloud needs to confirm that you own the domain and that your DNS records are set up correctly. This process is called verification. Occasionally, verification may appear stuck or time out entirely. This is usually because a DNS record is misconfigured or has not finished propagating (the process by which DNS changes spread across the internet). ## Before you start Add your records at the provider that actually serves DNS for your domain, which is not always where you purchased it. For example, if you registered at GoDaddy but pointed your nameservers to Cloudflare, you must add records in Cloudflare. Run the following command to check: ```bash theme={null} dig NS example.com +short ``` The output will list nameserver hostnames (e.g., `anna.ns.cloudflare.com`). Add your Laravel Cloud records at the provider that owns those nameservers. ## Add your DNS records Add **all** records Laravel Cloud shows, including `www` and wildcard records if they are enabled. If you chose pre-verification (proving ownership and issuing the SSL certificate before switching traffic), Cloud also shows an ownership verification record and SSL validation records. Record names and values must match exactly; even small differences, such as extra dots or missing prefixes, will cause verification to fail. ### Enter only the subdomain Most DNS providers have a host or name field that expects only the subdomain portion of a record name, not the full domain. Your provider appends the domain automatically: * For `www.example.com`, enter `www` * For `_cf-custom-hostname.example.com`, enter `_cf-custom-hostname` * For `_acme-challenge.example.com`, enter `_acme-challenge` * For `example.com` itself, most providers use `@` or leave the host blank If you paste the full name into this field, the domain is added twice, producing `_cf-custom-hostname.example.com.example.com` instead of `_cf-custom-hostname.example.com`. After saving a record, always re-open it in your provider's dashboard and confirm the assembled name matches exactly what Laravel Cloud shows. This is the most effective way to catch formatting mistakes early. ### Domain control validation records Some domains need a domain control validation (DCV) delegation record: a CNAME named `_acme-challenge` that points to Cloudflare, which Laravel Cloud uses to issue and renew your SSL certificates. Laravel Cloud shows this record when: * The domain is a wildcard domain (such as `*.example.com`), or belongs to a domain with a wildcard enabled, including its `www` domain * You chose **Cloudflare DNS and Proxy** for the domain, because your Cloudflare proxy would otherwise answer certificate validation requests before they reach Laravel Cloud Add the record at your DNS provider like any other record, and keep it in place after verification. Removing it prevents your certificate from renewing. ### Provider-specific instructions In Cloudflare, select your website and open **DNS**. Confirm you are editing DNS records in the correct Cloudflare account and zone. In Laravel Cloud, open your domain's configuration and copy the **origin** record(s). These records tell Cloudflare where to send traffic for your domain. For the record name in Cloudflare: * Use `@` for the root domain (e.g., `example.com`) * Use `www` for `www.example.com` * Use `*` for `*.example.com` (wildcards), if shown For proxy status (the orange or gray cloud icon in Cloudflare): * Origin records are typically safe to proxy (orange cloud) if you selected a Cloudflare proxy option in Laravel Cloud. * If you are unsure, start with the proxy status Laravel Cloud recommends in the UI. If Laravel Cloud shows an ownership verification record like `_cf-custom-hostname.example.com`, add it as a **TXT** record named `_cf-custom-hostname`. Laravel Cloud may show `_acme-challenge` records used to issue your domain's SSL certificate. Copy them exactly as shown. If an `_acme-challenge` record is a **CNAME**, such as a [DCV delegation record](#domain-control-validation-records), keep it set to **DNS only** (gray cloud) at all times. Proxying it will prevent the SSL certificate from being issued or renewed. If you are pre-verifying your domain and see Cloudflare-related verification errors, temporarily setting the hostname's record to **DNS only** may be required until verification completes. You can re-enable the proxy afterward. Unlike most providers, Route 53 accepts fully qualified record names, so you can paste the complete name from Laravel Cloud (e.g., `_cf-custom-hostname.example.com`) directly into the name field. Route 53 may add a trailing dot (e.g., `_cf-custom-hostname.example.com.`), which is standard DNS formatting and is expected. If you are not sure you are editing the correct hosted zone, confirm that the nameservers from the [`dig NS` check](#before-you-start) match the nameservers listed in your Route 53 hosted zone. GoDaddy's DNS editor calls the subdomain field **Host**. After saving, GoDaddy displays the full record name, so you can confirm there that it matches Laravel Cloud exactly, with no repeated or missing parts. Namecheap's DNS editor calls the subdomain field **Host**. For root-domain records (i.e., records for `example.com` itself), use `@` as the host value. Squarespace (which acquired Google Domains) has its own naming conventions, but the subdomain rule applies to any name or host field. For a wildcard `*.example.com`, enter `*`. ## Verification timeline Most domains verify within 15 minutes once the correct DNS records are publicly visible. However, propagation can take longer depending on your DNS provider and the record's TTL (time-to-live), a value that controls how long DNS results are cached before being refreshed. Laravel Cloud will automatically retry verification checks for approximately 12 hours. If verification still cannot complete after that period, the domain will time out and you may need to correct your DNS records and retry. ## Check your records in the terminal You can verify that your DNS records are publicly visible by running `dig` commands in your terminal. Replace `example.com` with your actual domain: ```bash theme={null} # Which DNS provider is responsible for your domain? dig NS example.com +short # Are your origin records (the records that point traffic to Laravel Cloud) resolving? dig A example.com +short dig CNAME example.com +short # Is the ownership verification record visible? dig TXT _cf-custom-hostname.example.com +short # Are the SSL validation records visible? (may be TXT or CNAME depending on your setup) dig TXT _acme-challenge.example.com +short dig CNAME _acme-challenge.example.com +short ``` If any command returns no output, that record is either missing or has not finished propagating. ## Common verification issues ### Missing `www` records when redirects are enabled Laravel Cloud's **Redirect from [www](http://www).** setting is enabled by default and is the recommended configuration. When enabled, Laravel Cloud will validate both `example.com` and `www.example.com`, which means DNS records are required for both hostnames. If you only added records for `example.com` and skipped `www`, verification can fail. Make sure you added records for both hostnames exactly as shown in the domain configuration screen. ### Records have propagated but the domain is still verifying If your records look correct when checked with `dig` or an external DNS tool, but the domain is still showing as **Verifying** or **Timed out** in Laravel Cloud, this may indicate that our network provider (Cloudflare) has flagged the domain for manual review. This can happen even if your domain is not hosted on Cloudflare, because Laravel Cloud uses Cloudflare's infrastructure behind the scenes to manage SSL certificates and routing. Cloudflare's automated systems occasionally flag domains due to potential abuse concerns. This is sometimes a false positive and requires intervention on the Cloudflare side to resolve. If you believe this is affecting your domain, [contact support](#when-to-contact-support) so the team can assist. ## When to contact support If your domain is still stuck after working through this guide, contact support through the **Help** portal in your Laravel Cloud dashboard. To help the team diagnose the issue quickly, include: * Your domain name * Screenshots of the DNS records as they appear in your DNS provider's dashboard * The output from the commands in [Check your records in the terminal](#check-your-records-in-the-terminal) # Fix Environment Not Sleeping Issues Source: https://cloud.laravel.com/docs/knowledge-base/environment-not-sleeping Troubleshoot and fix Laravel Cloud environments that won't scale to zero. [Scale-to-Zero](/docs/compute#scale-to-zero) is enabled by default on Flex compute instances. If you change this setting, you will need to **Save and Redeploy** your environment for it to take effect. Even when you aren't actively using your application, it can still receive requests that wake it from sleep: * Simple vanity domains can occasionally be found by bots scanning for active web pages to index. Consider using the auto-generated domain or choosing a more complex vanity domain to reduce stray bot traffic. * Custom domains may have existing traffic patterns, such as being regularly crawled or indexed by bots. Laravel Cloud blocks many such instances, but it is not always possible to differentiate regular requests from automated ones. * Links posted into common messaging applications, like Slack, can automatically "visit" your site in order to access thumbnails and other metadata about your site. * Applications that use WebSockets may delay the sleep timer. Because your environment also wakes automatically to run [scheduled tasks](/docs/scheduled-tasks) and process [queued jobs](/docs/queues), a wake interval at or below your sleep timeout can keep the environment awake continuously: * A scheduled task or manual wake interval that runs more frequently than the sleep timeout will wake the environment before it can sleep. For example, a task that runs every 5 minutes with a 5-minute sleep timeout means the environment never reaches the timeout and never sleeps. * To resolve this, set your sleep timeout shorter than your most frequent wake interval, or space out your scheduled tasks. Databases that support Scale-to-Zero, such as Serverless Postgres and Laravel MySQL Flex, are configured separately. As with your app cluster, changing these settings requires **Save and Redeploy** to take effect. # Generating PDFs Source: https://cloud.laravel.com/docs/knowledge-base/generating-pdfs Learn how to generate PDFs with Laravel in Laravel Cloud. This guide is for Laravel applications. You may generate PDFs in Laravel Cloud by leveraging [Cloudflare's Browser Rendering API](https://developers.cloudflare.com/browser-rendering/rest-api/pdf-endpoint/#convert-custom-html-to-pdf). To get started, generate a Cloudflare API token that has the `Account.Browser Rendering` permission and locate your Account ID from your Cloudflare dashboard URL. ## Using Laravel PDF [Spatie's Laravel PDF](https://spatie.be/docs/laravel-pdf) package provides a convenient wrapper around Cloudflare's Browser Rendering API via its built-in Cloudflare driver. No Node.js or Chrome binary is required on your instances. First, install the package via Composer: ```bash theme={null} composer require spatie/laravel-pdf ``` Then, add the following environment variables to your Cloud environment's environment variable settings: ```dotenv theme={null} LARAVEL_PDF_DRIVER=cloudflare CLOUDFLARE_API_TOKEN=your-api-token CLOUDFLARE_ACCOUNT_ID=your-account-id ``` Once configured, you may generate PDFs using the `Pdf` facade. For example, the following controller method renders a view as a PDF and streams it as a download to the browser: ```php theme={null} use Spatie\LaravelPdf\Facades\Pdf; public function download() { return Pdf::view('pdfs.invoice', ['invoice' => $invoice]) ->format('a4') ->download('invoice.pdf'); } ``` For more information on available options such as custom paper sizes, margins, headers, and footers, please refer to the [Laravel PDF documentation](https://spatie.be/docs/laravel-pdf). ## Using Laravel Cashier with Laravel PDF Cashier's default invoice PDF renderer uses Dompdf, which does not work in Laravel Cloud. To generate Cashier invoices on Cloud, install Spatie's Laravel PDF package and configure the Cloudflare environment variables as described [above](#using-laravel-pdf): ```bash theme={null} composer require spatie/laravel-pdf ``` Then, set Cashier to use its built-in Laravel PDF invoice renderer by adding the following environment variable to your Cloud environment's environment variable settings: ```dotenv theme={null} CASHIER_INVOICE_RENDERER=Laravel\Cashier\Invoices\LaravelPdfInvoiceRenderer ``` Cashier will automatically resolve this renderer at runtime and use Spatie Laravel PDF when generating invoice downloads. ## Manual Usage If you prefer to call the Cloudflare API directly without an additional dependency, add a `cloudflare` entry to your `services.php` config file: ```php theme={null} 'cloudflare' => [ 'api_token' => env('CLOUDFLARE_API_TOKEN'), 'account_id' => env('CLOUDFLARE_ACCOUNT_ID'), ], ``` Next, set these environment variables in your Cloud environment's environment variable settings. Now you may call the Cloudflare PDF API using Laravel's built-in `Http` facade. The following example demonstrates how to generate HTML from a view and stream the response as a downloadable PDF to the browser from a controller method: ```php theme={null} use Illuminate\Support\Facades\Http; public function download() { return response()->streamDownload(function () { $token = config('services.cloudflare.api_token'); $accountId = config('services.cloudflare.account_id'); echo Http::withToken($token) ->post('https://api.cloudflare.com/client/v4/accounts/'.$accountId.'/browser-rendering/pdf', [ 'html' => view('view-to-render')->render(), ]) ->body(); }, 'file.pdf', [ 'Content-Type' => 'application/pdf', ]); } ``` # Knowledge Base Source: https://cloud.laravel.com/docs/knowledge-base/intro Browse helpful guides and articles for Laravel Cloud setup, deployment, and troubleshooting. Welcome to Laravel Cloud's knowledge base. Here you will find guides and troubleshooting articles tailored to common questions or issues you may face when using Cloud. Use the sidebar navigation (or navbar menu on mobile) to see the available articles. If you need further assistance or would like to suggest a new KB topic, please contact support by clicking the "chat" button in the bottom/right of your screen. # Understanding Logs Source: https://cloud.laravel.com/docs/knowledge-base/logs Learn about common application logs when using Laravel Cloud. ## \[error] Access forbidden by rule As is common for many websites on the internet, bots may often scan trying to find vulnerabilities on your website. When a bot tries to request access to a page that does not exist, or is explicitly blocked by Laravel Cloud for security purposes, you may see related `[error]` logs. These can be safely ignored. ```shell theme={null} Example logs: 2025-03-26 17:26:05 UTC 2025/03/26 17:26:05 [error] 148#148: *35409 access forbidden by rule, client: 2600:1f16:e0:8506:ea9f::8, server: _, request: "GET /config/php.ini HTTP/1.1", host: "yourWebsite.com" 2025-03-26 17:26:18 UTC 2025/03/26 17:26:18 [error] 150#150: *35439 access forbidden by rule, client: 2600:1f16:e0:8506:b40f::6, server: _, request: "GET /.aws/credentials HTTP/1.1", host: "yourWebsite.com" 2025-03-26 17:26:24 UTC 2025/03/26 17:26:24 [error] 150#150: *35455 access forbidden by rule, client: 2600:1f16:e0:8506:ea9f::8, server: _, request: "GET /config.ini HTTP/1.1", host: "yourWebsite.com" ``` *** ## fatal: not a git repository Some packages may attempt to access your `.git` directory during runtime in your application. When using Laravel Cloud, the `.git` folder is removed during the deploy process, meaning this directory is unavailable at runtime, which can trigger this error for packages that depend on this. For example, having Sentry installed will allow you the option to run Git to grab the current commit hash, thus triggering these errors. If a package depends on your deployment's Git hash being available, you can inject it as an environment variable by adding the following to your build commands: ```bash theme={null} # Install production dependencies... composer install --no-dev # Add the Git commit hash to an environment variable... echo -e "\nSENTRY_RELEASE=`git log --pretty="%h" -n1 HEAD`" >> .env # Cache the configuration to make SENTRY_RELEASE available at runtime... php artisan config:cache ``` *** ## \[truncated due size] The message `[truncated due size...]` log is indicating that a log message exceeded a size limit, causing the message to be cut off. This typically happens when logs or error messages are too lengthy. This can be common during your deployment process. To reduce the size of the content printed out for your deploy commands, you can reduce the commands' verbosity through additional flags: ``` composer install --no-dev --quiet npm ci --quiet --no-progress ``` Note that if your application is in `APP_DEBUG=true`, errors will produce a full stack track which can be truncated. # Manage robots.txt Source: https://cloud.laravel.com/docs/knowledge-base/managing-robots Learn how to customize the robots.txt file in Laravel Cloud and manage crawler access for better SEO. The `robots.txt` file is essential for controlling search engine crawlers' access to your site. It provides information on which pages and sections can be visited by web crawlers. If you need to customize the contents of this file when your application is being deployed, you can add a command to the **Build Commands** section of your environment's deployment settings. For example, if you want to disallow crawling any part of your website: 1. Visit your application environment 2. Open its **Settings** page 3. On the **Deployments** section of the Settings page. Under the **Build commands** section, add: ```shell theme={null} echo -e "User-agent: *\nDisallow: /" > public/robots.txt ``` ## Cloudflare reserved paths and SEO Laravel Cloud utilizes Cloudflare's CDN service, which automatically reserves the `/cdn-cgi` path on all hosted domains. This path appears on your domain as `https://www.example.com/cdn-cgi/l/email-protection` and similar endpoints. These `/cdn-cgi` endpoints are: * Automatically generated by Cloudflare's service * Managed entirely by Cloudflare * Cannot be modified or customized For optimal SEO performance, consider adding the following directive to your `robots.txt` file to exclude these paths from search engine crawling: ``` Disallow: /cdn-cgi/ ``` For additional technical details about Cloudflare's CDN endpoints, refer to [Cloudflare's developer documentation](https://developers.cloudflare.com/fundamentals/reference/cdn-cgi-endpoint). # Migrate from Queue Clusters Source: https://cloud.laravel.com/docs/knowledge-base/migrate-from-queue-clusters Learn how to move your queue workers off a deprecated queue cluster to a managed queue or a worker cluster before queue clusters are retired. [Queue clusters](/docs/workers#queue-clusters-deprecated) are deprecated and are being retired on September 30, 2026. Their replacements are: * **[Managed queues](/docs/queues#managed-queues) (recommended)**, where Laravel Cloud provisions all the infrastructure needed to run a queue (compute, driver, and monitoring) and runs and scales the workers for you * [Worker clusters](/docs/workers#worker-clusters), where you manage `queue:work` yourself on compute that is separate from your web traffic This guide walks through moving a queue cluster's workload to either option. Existing queue clusters continue processing jobs until **September 30, 2026**. After that date they stop processing jobs, and anything still dispatched to the queues they served will wait unprocessed until a replacement worker picks it up. How long those jobs survive depends on your queue driver: Redis and database queues keep them indefinitely, while an SQS connection drops them after its message retention period (14 days at most). Migrate production queue clusters well before then. The first generation of managed queues also retires on September 30, 2026. Those run on SQS, so jobs are retained for a maximum of 14 days before being lost. If you also have a managed queue that needs upgrading, see [Upgrading from earlier managed queues](/docs/queues#upgrading-from-earlier-managed-queues). A queue cluster runs `php artisan queue:work` against your application's own queue driver (`redis`, `database`, your own SQS, or whatever your configured connection points at) and scales its worker count on job latency and queue pressure. Neither replacement is a one-to-one copy of that. * A managed queue swaps your queue driver for one that Laravel Cloud provisions, then scales workers on the work waiting to be processed, including down to zero. * A worker cluster keeps your driver and your `queue:work` command exactly as they are, but scales on CPU and memory rather than on queue depth. Both paths start by creating and deploying the replacement, then verifying that jobs can flow through it. For a managed queue, switch dispatching to the `cloud` connection and let the old connection drain before deleting the queue cluster. A worker cluster keeps the existing connection, so both clusters process its backlog until you delete the queue cluster. Deleting the queue cluster is the one step you cannot undo. Before you do it, confirm all of the following: * The replacement has processed a test job on every queue name the cluster served. * `queue:monitor` reports zero jobs on the old connection, including delayed jobs. * Failed jobs have been retried or deleted. A retried failed job is re-dispatched onto the connection recorded on it, so a retry after the cutover can land on the old connection with no worker left to run it. * You have a copy of the queue cluster's settings, since they are discarded with it. ## Before you start Open the queue cluster on your environment's infrastructure canvas and write down its settings: the connection, the queue name or names it processes (a single queue cluster may serve a comma-separated list such as `emails,notifications`), and the worker options (backoff, sleep, rest, timeout, tries, max-jobs, max-time, and force). You will recreate these on the replacement, and they disappear with the queue cluster when it is deleted. If you are not sure which queue names your application dispatches to, check the `queue` value of your connection in `config/queue.php`, then search your code for explicit queue names: ```sh theme={null} grep -rn "onQueue(" app/ ``` Here is how each queue cluster setting maps onto the replacements: | Queue cluster setting | Managed queue | Worker cluster | | - | - | - | | Connection (`redis`, `database`, `SQS`, ...) | Replaced by the `cloud` connection Laravel Cloud injects | Copied one-to-one | | Queue names (`emails,notifications`) | One managed queue per name | Copied one-to-one into one background process | | backoff, sleep, rest, timeout, tries, force | No worker flags to set; Laravel Cloud manages pickup and visibility. Per-job `$tries` and `$backoff` on the job class still apply | Copied one-to-one into the worker form | | max-jobs, max-time | Not needed | Custom worker with the full `queue:work` command | | Worker count, scaled on job latency and queue pressure | Autoscaling range, scaled on the work waiting | Processes times replicas, scaled on CPU and memory | | Failed jobs | Queues dashboard and API | Your application's failed job driver, as today; no visibility in Laravel Cloud | Then check the one thing that decides your path: whether your jobs depend on behavior specific to your current driver. Redis-specific queue features, per-job delays longer than 15 minutes, and strict ordering are the usual reasons to keep the driver. Queue clusters and worker clusters are available on the same plans, so plan is not a factor. | Path | Use when | What changes | | - | - | - | | [Managed queue](#move-to-a-managed-queue) | You want Laravel Cloud to run and scale the workers, and your jobs do not depend on driver-specific behavior | Jobs move to the `cloud` connection. Workers scale on the work waiting, and to zero when idle. Failed jobs appear on the Queues dashboard. | | [Worker cluster](#move-to-a-worker-cluster) | You must keep your own driver (Redis or Valkey, database, your own SQS) or rely on driver-specific queue behavior | Nothing changes in your application. Workers run on a separate cluster that scales on CPU and memory. | Managed queues are the right destination for most applications, and the one we recommend. Choose a worker cluster when your application must keep its current driver. ## Move to a managed queue Managed queues require Laravel 11.55.0, 12.63.0, 13.19.0, or newer, with `aws/aws-sdk-php` in your `composer.json`. Laravel Cloud reads your `composer.lock` at deploy time, so update the framework, commit the lock file, and deploy before you create the queue. A deployment that creates a managed queue without the SDK fails with a clear error. Symfony applications are supported via [`laravel/symfony-on-cloud`](https://github.com/laravel/symfony-on-cloud). See [Requirements](/docs/queues#requirements). Click **Add compute** on the canvas toolbar, then **Managed queue**. Each managed queue handles exactly one Laravel queue name, so a queue cluster processing `emails,notifications` becomes two managed queues, one named `emails` and one named `notifications`. Name each queue exactly as your application dispatches to it. The first managed queue you create becomes the environment's default and receives any job dispatched without a queue name; see [Setting a default queue](/docs/queues#setting-a-default-queue). For [memory](/docs/queues#memory-allocation), start close to the queue cluster's compute size (256 MiB covers typical email, webhook, and record-update jobs) and adjust after watching the Memory chart on the Queues dashboard. For the [worker autoscaling range](/docs/queues#worker-autoscaling), set the maximum by how much parallelism your database and third-party APIs can absorb, not by the queue cluster's worker count. The two scale differently, so that number does not carry over. Queue and worker allowances vary by plan; see [Managed queues](/docs/queues#managed-queues) for the current limits. Deploying a managed queue sets `QUEUE_CONNECTION=cloud` for the environment. From that deployment on, every job dispatched without an explicit connection, including the jobs your queue cluster processes today, goes to managed queues. This is usually exactly what you want. If some jobs must stay on your previous driver, set `QUEUE_CONNECTION` back to it as a custom environment variable and dispatch managed-queue jobs on the `cloud` connection explicitly: ```php theme={null} ProcessPodcast::dispatch($podcast)->onConnection('cloud'); ``` The details are in [Queue connection](/docs/queues#queue-connection). Deploy the environment. Laravel Cloud provisions each queue and starts its worker pool. Dispatch a test job to every queue name and watch it process on the **Queues** dashboard under the environment's **Monitoring** tab. Because the default connection switched with this deployment, the queue cluster stops receiving new jobs unless you pinned `QUEUE_CONNECTION` in the previous step or jobs explicitly target the old connection. When neither applies, it works through only the jobs already on the old connection. Leave the queue cluster running until the old connection is empty. Check from the Commands tab, substituting your own connection and queue names: ```sh theme={null} php artisan queue:monitor redis:emails,redis:notifications ``` The reported size includes delayed and reserved jobs, so zero means genuinely done. Delayed jobs and pending retries are the ones most likely to be left behind, since they sit on the old connection until their time comes. Then remove the queue cluster from the infrastructure canvas and deploy. Deleting it stops its workers immediately and discards its settings. Any job still on the old connection at that point is never processed. Until you delete the queue cluster, the move is reversible. To roll back, set `QUEUE_CONNECTION` to your previous driver as a custom environment variable and deploy. New jobs return to the old connection and the queue cluster picks them up again. Jobs already sitting on a managed queue stay there until its workers finish them; deleting the managed queue discards them. Remove the managed queue from the canvas too if you are not keeping it. ### What behaves differently A managed queue is not the same queue your cluster was working. Expect these differences, all covered in more depth under [Limitations](/docs/queues#limitations): * Standard queues deliver each job at least once with best-effort ordering. Design jobs to tolerate a second run, or create a [FIFO queue](/docs/queues#queue-types) for order-sensitive work. * Delays are capped at 15 minutes on standard queues, and FIFO queues do not support per-job delays at all. Search your code for `->delay()` and `release()` calls beyond that window before you migrate. * Jobs on the Flex class should finish within 90 seconds. Longer jobs belong on the [Pro class](/docs/queues#compute-classes), which has no fixed limit. * The `queue:failed`, `queue:retry`, and `queue:clear` Artisan commands are not supported. Failed jobs are listed, retried, and deleted from the Queues dashboard or the Laravel Cloud API instead. For per-job tracing that spans web requests and workers regardless of which queue backs them, [Laravel Nightwatch](https://nightwatch.laravel.com) works the same before and after the move. ## Move to a worker cluster A worker cluster runs your `queue:work` command verbatim against your own driver, so nothing changes in your application. What you give up is the queue cluster's latency-based scaling, which this path replaces with CPU and memory scaling. On the infrastructure canvas, click **Add worker cluster**. Choose a compute size in the same range as the queue cluster's, since it will run the same jobs, and size it independently of the app cluster: a worker cluster never serves HTTP traffic. See [Worker clusters](/docs/workers#worker-clusters). Click the new Worker cluster, then in the **Background processes** section click **New background process**. Copy the queue cluster's connection, queue names, and worker options (backoff, sleep, rest, timeout, tries, and force) into the worker form one-to-one. The queue field accepts the same comma-separated list, so one background process replaces one queue cluster. If your queue cluster relied on max-jobs or max-time, which the worker form does not expose, use the **Custom worker** tab instead and enter the full `php artisan queue:work` command with those flags: ```sh theme={null} php artisan queue:work redis --queue=emails,notifications --tries=3 --backoff=10 --timeout=90 --max-jobs=1000 --max-time=3600 ``` See [Custom background processes](/docs/workers#custom-background-processes) for how custom workers behave. Each background process runs between 1 and 10 processes, and that number is multiplied by the cluster's replica count. A worker with 4 processes on a cluster running 3 replicas is 12 `queue:work` processes hitting your database at once. Choose a process count that fits comfortably in one replica's memory, then pick a fixed replica count or a minimum and maximum range under [Autoscaling](/docs/compute#autoscaling). The maximum replica count depends on your plan. If the app cluster scales to zero, the worker cluster can either stay awake at all times or sleep alongside the app cluster (Flex compute only, since Pro does not scale to zero). A sleeping worker cluster stops when the app cluster's sleep timeout elapses, even if a job is still running, so keep the worker cluster awake when it runs your queue workers. See [Queue workers and Scale to Zero](/docs/queues#queue-workers-and-scale-to-zero). Deploy the environment. Both the queue cluster and the worker cluster now consume the same queues from your driver, which is safe: each job is reserved by one worker or the other. Watch the worker's output in the [Logs](/docs/logs) tab under **Monitoring** and its CPU and memory on the Metrics tab, and confirm jobs complete. Laravel Cloud restarts a background process automatically if it exits, and `queue:restart` is not needed after deployments. Once the worker cluster is keeping up, remove the queue cluster from the canvas and deploy. Because both clusters read the same queue, no jobs are stranded; the worker cluster takes over the whole backlog. Deleting the queue cluster stops its workers immediately and discards its settings, so confirm the worker background process is saved with everything you copied in step 2 before you delete. Until you delete the queue cluster, rolling back is just removing the worker cluster from the canvas and deploying. Jobs the worker cluster was processing at that moment are released back to the queue after your driver's `retry_after` window and picked up by the queue cluster, so nothing is lost, though those jobs run twice. Worker clusters scale on CPU and memory, never on queue depth. A backlog of cheap jobs that mostly wait on the network may never push CPU high enough to add a replica, so a queue cluster that "just kept up" can fall behind on a worker cluster with the same size. To compensate, set the minimum replica count for your peak rather than your average, or, on the Business and Enterprise plans, use [scheduled autoscaling](/docs/compute#scheduled-autoscaling) to raise the minimum ahead of known bursts. If you want scaling driven by the work waiting, that is what [managed queues](#move-to-a-managed-queue) do. ## Using an AI agent An AI coding agent can help with this migration when it has this guide, your application's repository, and an authenticated [Laravel Cloud CLI](/docs/api/cli). Ask the agent to assess the application first, then approve each billable or irreversible step yourself. ```text theme={null} Read https://laravel.com/cloud/docs/knowledge-base/migrate-from-queue-clusters and assess this application's migration off its Laravel Cloud queue cluster. Make no changes yet. Inspect config/queue.php, the environment's QUEUE_CONNECTION, and the queue cluster on the environment canvas: note its connection, every queue name it processes, and its worker options. Search the repository for Redis-specific queue features, ->delay() or release() calls longer than 15 minutes, and jobs that run longer than 90 seconds. Recommend a managed queue or a worker cluster, explain what changes for the application, and show the complete plan. After I approve the plan, make any code changes on a branch and show me the diff before committing. Stop and ask before creating a managed queue or worker cluster (both are billable), before any deployment that changes QUEUE_CONNECTION, and before deleting the queue cluster. Do not delete the queue cluster until I confirm the old connection is empty and the replacement is processing jobs. ``` ## Need help? If you get stuck, or your queue cluster runs something this guide does not cover, contact support from the **Help** portal in your Laravel Cloud dashboard before you delete anything. When you reach out, include the environment, the queue cluster's name, its connection and queue names, and which path you have chosen (managed queue or worker cluster) so the team can help quickly. # Migrate an Application to a Different Region Source: https://cloud.laravel.com/docs/knowledge-base/migrate-to-different-region Learn how to move your Laravel Cloud application to a different region. To move your application and its resources to a new region, create the new regional infrastructure first, then cut traffic over. This guide walks you through each step. ## Before you start You cannot perform this migration in place. You will run old and new environments in parallel until cutover. Downtime is possible, especially during database cutover, so plan accordingly (for example, schedule a maintenance window and take backups). If you use private database connectivity, your database region must match your application region. ## Step 1: Create the new application Create a new application in the target region using the same repository. Then recreate each environment, matching branch names and settings from the original application. ## Step 2: Migrate the database Laravel Cloud does not provide cross-region database copy or restore. Complete the migration manually: 1. Export data from the current database (for example, `mysqldump`, `pg_dump`, or a Neon export). 2. Create a new database cluster and database in the target region via the normal create flow. 3. Import your data into the new database. 4. Attach the new database to the new application's environments. Do not detach or delete the original database until you have verified cutover. ## Step 3: Migrate the cache Cache data migration is not handled by the platform. The process depends on whether cache data must be preserved: 1. Create a new cache in the target region. 2. Attach it to your new environments. 3. If data must be preserved, implement dual writes in your application before switching reads to the new cache. 4. Delete the old cache once you've cut over. If your cache is ephemeral (such as sessions or rate-limiting state), you can skip data migration and start with a fresh cache. ## Step 4: Migrate WebSockets (Reverb) 1. Create a new Reverb WebSocket cluster in the target region. 2. Attach it to the new environments. 3. Delete the old cluster after cutover. ## Step 5: Copy environment configuration Manually copy configuration from each old environment to its corresponding new environment: * Environment variables * Build and deploy settings * Vanity domains ## Step 6: Deploy and verify Deploy each environment in the new application, then verify: * Deployments complete successfully * Database connectivity works * Cache is functioning * WebSocket connections are established * Logs are appearing (logs are region specific through OpenSearch) ## Step 7: Migrate domains To move your domains to the new application: 1. Go to the old environment's **Network settings**. 2. Open the **...** dropdown on each domain. 3. Click the **Move** option. 4. Follow the dialog instructions and select the new environment as the target. 5. Redeploy the new application so `APP_URL` is updated. Primary domains cannot be moved between environments. First, choose **Unset as primary** in the domain dropdown. After the move completes, set the domain as primary in the new application. ## Step 8: Clean up Once you've confirmed everything is working in the new region: * Delete or archive the old database cluster, cache, and WebSocket cluster * Delete the old application # Migrate from Redis by Upstash to Laravel Valkey Source: https://cloud.laravel.com/docs/knowledge-base/migrate-upstash-to-valkey Learn how to migrate your application's cache, sessions, queues, and Redis data from Redis by Upstash to Laravel Valkey. [Redis by Upstash](/docs/resources/caches/redis) is deprecated and scheduled to be sunset. Its replacement is [Laravel Valkey](/docs/resources/caches/valkey), a fully managed, Redis-compatible cache with better performance and per-second billing. This guide walks through moving an environment from an Upstash cache to a Valkey cache. Beginning **October 1, 2026**, Upstash will resume enformcing the monthly data transfer allowance included with each cache size. Depending on your auto-upgrade settings, this may result in your cache being upgraded to the next size up, or your connections being disabled for the remainder of the month. See [Bandwidth limits and auto-upgrades](/docs/resources/caches/redis#bandwidth-limits-and-auto-upgrades) for details, and check your cache's metrics to see how close it is to its allowance. Redis by Upstash pricing also increases on **November 30, 2026** to align with Upstash's list pricing. Eligible customers who migrate to [Laravel Valkey](/docs/resources/caches/valkey) and delete their Upstash cache before that date will receive a Cloud credit based on two months of the cache's monthly price. See the [pricing page](/docs/pricing#redis-by-upstash) for the current and upcoming prices. Existing Redis by Upstash caches will remain available until **August 31, 2027** under the higher pricing and bandwidth limits, after which any remaining caches will be deleted. Valkey is compatible with the Redis API your application already uses, so your application code does not need to change. Migrating is really about two things: pointing your environment at the new store, and deciding what, if anything, must happen to the data in the old one. [Laravel Valkey](/docs/resources/caches/valkey) is the right destination for most applications. Enterprise customers on [Private Cloud](/docs/private-cloud) may instead migrate to a managed AWS [ElastiCache](/docs/private-cloud/elasticache) cache, available in both Valkey and Redis OSS engines, which adds automatic failover and multi-AZ deployments. Either way the destination is a Redis-compatible store, so every path in this guide applies unchanged. To provision ElastiCache, [contact us](https://cloud.laravel.com/enterprise). ## Before you start An environment has one attached cache at a time. Replacing it updates the injected `REDIS_*` environment variables on the next deployment. Detaching a cache does not delete it, so your Upstash cache remains available and billable until you delete it from your organization's Resources page. Its credentials remain valid, allowing a side-by-side migration. The `UPSTASH_*` and `VALKEY_*` variables used in this guide are temporary and used only by the migration tooling. Remove them when the migration is complete. First, work out what your application actually keeps in its cache, since that determines how careful you need to be: | Setting | What you are storing | | - | - | | `CACHE_STORE=redis` | Application cache, plus cache-based rate limiters and atomic locks | | `SESSION_DRIVER=redis` | User sessions | | `QUEUE_CONNECTION=redis` | Queued jobs, including delayed jobs and pending retries | | `Redis` facade usage in your code | Anything your application writes to Redis directly | Then pick your path: | Path | Use when | Downtime | | - | - | - | | 1. [Start fresh](#start-fresh) | Cache only, or you can tolerate losing sessions and pending jobs | None | | 2. [Drain your queues](#drain-your-queues) | You must not lose queued jobs or sessions | None | | 3. [Copy the data](#copy-the-data) | Long-lived data you cannot lose or wait out | Maintenance window | ## Start fresh If Upstash only backs your application's cache, there is no data worth moving. Caches rebuild themselves. On your environment's canvas, open the "..." menu on the cache card and choose "Replace", then select a [Laravel Valkey](/docs/resources/caches/valkey) cache, creating one if needed. Replacing only re-points the environment at the new cache; nothing changes for your running application until the next deployment. Redeploy the environment. The injected `REDIS_*` variables now point at Valkey. Once you have verified the application, delete the Upstash cache from your organization's Resources page. Detached caches continue to bill until deleted. The new cache starts empty, so cache reads miss until it rebuilds. On high-traffic applications, deploy during a low-traffic window to limit the temporary increase in database load. Redis-backed sessions reset, so users must sign in again and forms submitted across the cutover may receive a `419 Page Expired` response. Use the [session drain](#keeping-users-signed-in) if that is unacceptable. Atomic locks and rate limiters also reset, so a `withoutOverlapping` scheduled task or a `ShouldBeUnique` job could run twice during the deployment. If `QUEUE_CONNECTION=redis`, any jobs still in the old store, including delayed jobs, will never be processed after the swap. Check before you cut over by running `php artisan queue:monitor redis:default` from the Commands tab (list each queue name you dispatch to). If the count is not zero and those jobs matter, use [Path 2](#drain-your-queues) instead. ## Drain your queues Queue data changes while your application runs, so do not copy it between stores. Instead, run both stores side by side. New jobs dispatch to Valkey while a worker drains the jobs that remain on Upstash. Before swapping the cache, copy the current values of `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`, and `REDIS_SCHEME` from your environment's variables into new custom variables: `UPSTASH_REDIS_HOST`, `UPSTASH_REDIS_PORT`, `UPSTASH_REDIS_PASSWORD`, and `UPSTASH_REDIS_SCHEME`. Because these mirror the values your application connects with today, they are guaranteed to be in the right format. Add a Redis connection for the old store in `config/database.php`: ```php theme={null} // config/database.php, inside the 'redis' array... 'upstash' => [ 'host' => env('UPSTASH_REDIS_HOST'), 'password' => env('UPSTASH_REDIS_PASSWORD'), 'port' => env('UPSTASH_REDIS_PORT', '6379'), 'scheme' => env('UPSTASH_REDIS_SCHEME', 'tls'), 'database' => env('REDIS_DB', '0'), ], ``` And a queue connection that uses it in `config/queue.php`: ```php theme={null} // config/queue.php, inside the 'connections' array... 'upstash' => [ 'driver' => 'redis', 'connection' => 'upstash', 'queue' => env('REDIS_QUEUE', 'default'), 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), 'block_for' => null, 'after_commit' => false, ], ``` Commit these changes. Attach the Valkey cache to the environment and deploy. From this moment, every `dispatch()` lands on Valkey, since the default Redis connection now resolves to the new store. Your cache and sessions cut over in the same deployment, so the expectations from [Path 1](#start-fresh) apply to them here. Add a [background process](/docs/workers#app-cluster-background-processes) running `php artisan queue:work upstash` and deploy. If you dispatch to multiple queues, list them: `php artisan queue:work upstash --queue=default,emails`. For a small backlog with no delayed jobs, a one-off run of `php artisan queue:work upstash --stop-when-empty` from the Commands tab is enough. Check progress from the Commands tab with `php artisan queue:monitor upstash:default` (again, listing each queue name). The reported size includes delayed and reserved jobs, so zero means genuinely done. Be careful relying on `--stop-when-empty` as your completion signal: it exits as soon as no job is ready right now, even if delayed jobs are still scheduled for the future. `queue:monitor` is the source of truth. Retry or delete failed jobs before removing the old connection, since a retried job is re-dispatched onto the connection recorded on the failed job. Then remove the drain worker, the two config blocks, and the `UPSTASH_*` variables, deploy, and delete the Upstash cache from the Resources page. If you run Horizon, keep it pointed at the default connection and drain the old store with a plain `queue:work` background process. Horizon's internal state lives in Redis, so its dashboard metrics reset at the swap. For job-level visibility that survives the migration, [Laravel Nightwatch](https://nightwatch.laravel.com) traces queue jobs independently of which store backs them. If you are rethinking your queue setup anyway, consider draining to [managed queues](/docs/queues#managed-queues) instead of Valkey. The pattern is identical: create the managed queue so new jobs dispatch to the `cloud` connection, then drain the old Redis store with the same worker and monitor commands. ## Keeping users signed in By default, sessions reset at the swap and users sign in again. If that is unacceptable (long-lived logins, carts kept in the session, an active admin panel), sessions can be drained just like queues, using a temporary read-through session handler that checks the new store first and falls back to the old one. Laravel saves the session at the end of every request. After cutover, the first request from a returning visitor reads their session from Upstash through the fallback and writes it to Valkey. Redis-backed sessions expire `SESSION_LIFETIME` minutes (120 by default) after the user's last request, so keep the fallback in place for one session lifetime after cutover. Any session that remains on Upstash after that period has expired normally. Reusing the `upstash` Redis connection from the [drain](#drain-your-queues) setup, define a cache store for it in `config/cache.php`: ```php theme={null} // config/cache.php, inside the 'stores' array... 'upstash-sessions' => [ 'driver' => 'redis', 'connection' => 'upstash', ], ``` Create the handler: ```php theme={null} new->read($id) ?: $this->old->read($id); } public function write($id, $data): bool { return $this->new->write($id, $data); } public function destroy($id): bool { $this->new->destroy($id); $this->old->destroy($id); return true; } public function open($path, $name): bool { return true; } public function close(): bool { return true; } public function gc($max_lifetime): int { return 0; // Expiry is handled by the cache TTLs... } } ``` Register it as a session driver in the `boot` method of `app/Providers/AppServiceProvider.php`: ```php theme={null} use App\Sessions\DrainingSessionHandler; use Illuminate\Session\CacheBasedSessionHandler; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Session; Session::extend('drain', function ($app) { $minutes = $app['config']['session.lifetime']; return new DrainingSessionHandler( new CacheBasedSessionHandler(Cache::store('redis'), $minutes), new CacheBasedSessionHandler(Cache::store('upstash-sessions'), $minutes), ); }); ``` Set `SESSION_DRIVER=drain` so it deploys together with the cache swap. Note that `destroy` clears both stores, so signing out cannot be undone by the fallback, and rolling back mid-window is just an environment variable change. On Laravel Cloud, the injected configuration points the `default` and `cache` Redis connections at the same store and database, so the keys written here line up with the built-in `redis` session driver. Once one session lifetime has passed after cutover, set `SESSION_DRIVER` back to `redis` and re-deploy before deleting the Upstash cache. With the driver reverted, remove the handler, cache store, and connection with the rest of the drain teardown. Applications with very long session lifetimes should note the old cache must stay alive (and billing) for the whole window. ## Copy the data Sometimes the data itself must survive: your application stores long-lived values via the `Redis` facade, sessions you cannot invalidate, cache entries too expensive to rebuild, or delayed jobs scheduled further out than you can reasonably drain. Upstash does not expose Redis replication commands (`REPLICAOF`, `PSYNC`) to clients, so a live, zero-downtime replication into Valkey is not possible. Restoring an Upstash backup is not possible either: Upstash runs Redis 8.x, whose export format Valkey, which is Redis 7.2-compatible, cannot load, and `DUMP`/`RESTORE` fails for the same reason. The reliable path is a client-side copy that reads each key with its type's native commands and writes it to the new store, which is exactly what the Artisan command below does. A copy like this is point-in-time. Anything written to the old store after its key has been copied is silently lost, so you must freeze writes for the duration. **This path requires a maintenance window** roughly the length of the copy plus a deployment. Create the Valkey cache but do not attach it. Navigate to **Organization > Resources > Caches**, click the cache, and click **View credentials** at the top of the page. Add the connection details as custom environment variables: `VALKEY_REDIS_HOST`, `VALKEY_REDIS_PORT`, `VALKEY_REDIS_USERNAME`, and `VALKEY_REDIS_PASSWORD`. Copy the current injected `REDIS_*` values into `UPSTASH_*` variables as in [Path 2](#drain-your-queues). Set the maintenance mode variables so the "down" state is shared across instances and survives the cache swap: ```ini theme={null} APP_MAINTENANCE_DRIVER=cache APP_MAINTENANCE_STORE=database ``` The store must be `database`, not `redis`. Maintenance state kept in the cache you are migrating away from would be lost mid-migration. Add both Redis connections to `config/database.php`: ```php theme={null} // config/database.php, inside the 'redis' array... 'upstash' => [ 'host' => env('UPSTASH_REDIS_HOST'), 'password' => env('UPSTASH_REDIS_PASSWORD'), 'port' => env('UPSTASH_REDIS_PORT', '6379'), 'scheme' => env('UPSTASH_REDIS_SCHEME', 'tls'), 'database' => 0, 'prefix' => '', ], 'valkey' => [ 'host' => env('VALKEY_REDIS_HOST'), 'username' => env('VALKEY_REDIS_USERNAME'), 'password' => env('VALKEY_REDIS_PASSWORD'), 'port' => env('VALKEY_REDIS_PORT', '6379'), 'scheme' => 'tls', 'database' => 0, 'prefix' => '', ], ``` The empty `prefix` matters. `SCAN` returns raw keys that already carry your application's key prefix, so the copy connections must not apply a prefix of their own or every key would be double-prefixed on write. With an empty prefix, keys are copied byte-for-byte. Finally, add the [`cache:migrate` command](#the-migration-command) to your application, commit, and deploy. Nothing has changed for your users yet. From the Commands tab, run `php artisan cache:migrate --dry-run` to count keys by type without copying anything. As a rough planning figure, expect the copy to move a few hundred keys per second, and size your maintenance window accordingly. Run `php artisan down` from the Commands tab, then stop everything else that writes to Redis: pause any [managed queues](/docs/queues#pausing-and-purging), remove or scale down `queue:work` background processes, and disable the Scheduler toggle on your compute cluster (these changes deploy with the environment). `php artisan down` only stops web traffic; workers and the scheduler keep running until you stop them explicitly. Run `php artisan cache:migrate` from the Commands tab. The command replaces each destination key before writing, so it is idempotent and safe to re-run if interrupted. Attach the Valkey cache to the environment and deploy. Then compare key counts by running `php artisan cache:migrate --from=valkey --dry-run` against the source's earlier count. A small difference is normal, since keys with short TTLs expire during the window. Run `php artisan up`, re-enable the scheduler and workers, and resume any paused queues. After a burn-in period, remove the migration command, config blocks, and `UPSTASH_*` / `VALKEY_*` variables, and delete the Upstash cache from the Resources page. ### The migration command Use this command to copy every key from one Redis connection to another using each type's native read and write commands, preserving TTLs. It is written for phpredis, Laravel's default Redis client. If your application sets `REDIS_CLIENT=predis`, a few calls (such as `zAdd` argument order) need adapting. ```php theme={null} option('from')); $destination = $this->option('dry-run') ? null : Redis::connection($this->option('to')); $counts = []; $cursor = null; do { [$cursor, $keys] = $source->scan( $cursor, ['match' => '*', 'count' => (int) $this->option('chunk')] ) ?: [0, []]; foreach ($keys as $key) { $type = $this->typeOf($source, $key); if ($destination && ! $this->copy($source, $destination, $key, $type)) { $this->warn("Skipped [{$key}] of unsupported type [{$type}]."); continue; } $counts[$type] = ($counts[$type] ?? 0) + 1; } } while ((int) $cursor !== 0); $this->table( ['Type', $destination ? 'Copied' : 'Counted'], collect($counts)->map(fn ($count, $type) => [$type, $count])->values() ); return static::SUCCESS; } protected function copy(Connection $source, Connection $destination, string $key, string $type): bool { $ttl = $source->pttl($key); if ($ttl === -2) { return true; // The key expired mid-scan... } $destination->del($key); $copied = match ($type) { 'string' => $destination->set($key, $source->get($key)), 'hash' => $destination->hmset($key, $source->hgetall($key)), 'list' => $destination->rpush($key, ...$source->lrange($key, 0, -1)), 'set' => $destination->sadd($key, ...$source->smembers($key)), 'zset' => $destination->zadd($key, ...collect($source->zrange($key, 0, -1, true)) ->flatMap(fn ($score, $member) => [$score, $member])->all()), default => false, }; if ($copied !== false && $ttl > 0) { $destination->pexpire($key, $ttl); } return $copied !== false; } protected function typeOf(Connection $connection, string $key): string { $type = $connection->type($key); return match ($type) { \Redis::REDIS_STRING => 'string', \Redis::REDIS_SET => 'set', \Redis::REDIS_LIST => 'list', \Redis::REDIS_ZSET => 'zset', \Redis::REDIS_HASH => 'hash', \Redis::REDIS_STREAM => 'stream', default => is_string($type) ? strtolower($type) : 'unknown', }; } } ``` The command skips Redis streams, since consumer group state cannot be copied faithfully this way, and it reads each key's value in a single call, so extremely large individual keys (a hash with millions of fields, for example) may need chunked copying with `HSCAN` instead. Most Laravel applications are unaffected by either limitation. ## Using an AI agent An AI coding agent can help with this migration when it has this guide, your application's repository, and an authenticated [Laravel Cloud CLI](/docs/api/cli). Ask the agent to assess the application first, then approve each user-facing or irreversible step yourself. ```text theme={null} Read https://cloud.laravel.com/docs/knowledge-base/migrate-upstash-to-valkey and assess this application's migration from Redis by Upstash to Laravel Valkey. Make no changes yet. Inspect the Cloud environment's CACHE_STORE, SESSION_DRIVER, and QUEUE_CONNECTION settings; search the repository for Redis usage, delayed job dispatches, and queue names; and check each queue's backlog. Recommend a migration path, describe the cutover effects, and show the complete plan. After I approve the plan, make the code changes on a branch and show me the diff before committing. Stop and ask before swapping the cache, deploying, enabling maintenance mode, or deleting anything. Before teardown, verify that the old queue is empty or that the source and destination key counts match. Do not delete the Upstash cache until I confirm the application is healthy. ``` ## Need help? If you get stuck at any point, or you have an unusual cache workload you are not sure how to migrate, contact support from the **Help** portal in your Laravel Cloud dashboard before cutting over. It is far easier to talk through the approach in advance than to recover a migration that has already gone sideways. When you reach out, mention which path you are on and what your KV store is used for (cache, sessions, queues, or direct `Redis` usage) so the team can help quickly. # Migrate MySQL to PostgreSQL Source: https://cloud.laravel.com/docs/knowledge-base/migrating-mysql-to-postgresql Learn how to migrate from MySQL to hosted Serverless Postgres on Laravel Cloud. If you're moving to Laravel Cloud and prefer PostgreSQL, you can migrate from MySQL to Laravel **Serverless Postgres**, which scales to zero — meaning your database sleeps when idle, and you won’t be billed for unused compute time. Note that [**Laravel MySQL** Flex sizes can also scale to zero](/docs/resources/databases/laravel-mysql#scale-to-zero), so you no longer need to switch database engines to get a database that sleeps when idle. ### Migrating your data To move from MySQL to Postgres, you will need to: * Export your MySQL database (e.g., using `mysqldump`). * Use a tool like [**pgloader**](https://pgloader.io/) to import the data into your Serverless Postgres database. pgloader is specifically designed to convert MySQL databases to Postgres and handles much of the transformation automatically. Some tweaks may be needed depending on your schema, but many applications migrate cleanly with minimal effort. If you need more guidance, our database partner, **Neon**, has a helpful step-by-step guide: [Migrate from MySQL to Neon Postgres](https://neon.tech/docs/import/migrate-mysql). ### Application implementation considerations Keep in mind that although Postgres is very similar to MySQL, it is generally more strict in certain field definitions and usage. Below are common considerations which may be relevant to your application.
MySQL Postgres Considerations
Boolean Values Stores as `TINYINT` Stores as `BOOLEAN` Boolean casting works in Laravel, but avoid direct 0/1 comparisons in raw queries.
Auto-Increment IDs Uses AUTO\_INCREMENT Uses SERIAL Laravel handles this with \$table->id() or increments(), but raw SQL may need to be adjusted.
Unsigned Integers Supports unsignedInteger and unsignedBigInteger Must use signed bigInteger / foreignId() Although Laravel will silently handle conversions in your migration files, executing raw imports may reference UNSIGNED BIGINT columns. You will need to cast or redefine types on import.
UUIDs Stores as strings Has native UUID support If you have a custom UUID definition that does not match the specification, it will fail in Postgres. Use Laravel’s Str::uuid() helper to stay compatible.
Zero Dates Allows '0000-00-00' Invalid Date Use nullable() and avoid "zero dates"; Postgres will throw an error.
JSON Column Supported, but is not validated. Validates JSON on save. Ensure the JSON you store is valid, else Postgres save will fail.
Timestamp with Timezone `timestamp` does not store timezone detail Supports `timestamp` with and without timezone Laravel defaults to timestamp, so you must explicitly use \$table->timestampTz() if you want time zone-aware behavior.
Implicit Foreign Key Indexes Foreign key columns automatically receive corresponding index Indexes are not automatically created Explicitly add ->index() to any foreignId() columns to ensure indexes are created.
# Migrating Object Storage to Laravel Cloud Source: https://cloud.laravel.com/docs/knowledge-base/migrating-object-storage Learn how to move files from another storage provider to Laravel Cloud Object Storage using Laravel's read-through fallback disk. If you're moving an existing application to Laravel Cloud, you likely already have files sitting in another provider's bucket. Copying everything before you cut over can be slow and force downtime. Laravel's read-through filesystem driver lets you cut over immediately instead. Reads that miss on your new Laravel Cloud Object Storage bucket automatically fall back to your old provider and copy the file into the new bucket for next time, so your files migrate themselves as your application accesses them. ## Before you start The read-through driver requires Laravel 13.26.0 or later. Run `composer update laravel/framework` before continuing. If your old provider is S3-compatible, you'll also need `league/flysystem-aws-s3-v3`; see the [Object Storage prerequisites](/docs/resources/object-storage#prerequisites). This works for any two Flysystem-compatible disks, not just S3-compatible ones, so it also covers moving off local disk storage or another provider's driver. ## Step 1: Create your Laravel Object Storage bucket If you haven't already, [create a Laravel Object Storage bucket](/docs/resources/object-storage#creating-buckets) and attach it to your environment. Note its disk name (for example, `r2`); Laravel Cloud automatically injects the `AWS_*` credentials your application needs to reach it. Leave your old provider's credentials in place; you'll need them for the fallback disk in the next step. ## Step 2: Configure your old provider as a fallback disk In `config/filesystems.php`, add a disk entry for your old provider using whatever credentials it requires: ```php theme={null} 'disks' => [ // ... 'legacy' => [ 'driver' => 's3', 'key' => env('LEGACY_AWS_ACCESS_KEY_ID'), 'secret' => env('LEGACY_AWS_SECRET_ACCESS_KEY'), 'region' => env('LEGACY_AWS_DEFAULT_REGION'), 'bucket' => env('LEGACY_AWS_BUCKET'), 'endpoint' => env('LEGACY_AWS_ENDPOINT'), // omit for AWS S3; required for R2, Spaces, B2, etc. ], ], ``` Laravel Cloud only injects credentials for the bucket attached to your environment, so add your old provider's credentials as custom environment variables under your environment's settings. ## Step 3: Add a read-through disk Combine your new Laravel Cloud bucket (`primary`) and your old provider (`fallback`) into a single read-through disk: ```php theme={null} 'disks' => [ // ... 'assets' => [ 'driver' => 'read-through', 'primary' => 'r2', 'fallback' => 'legacy', ], ], ``` Reads check the new bucket first. If the file isn't there yet, Laravel reads it from the old provider, copies it into the new bucket, and returns it, all within the same request. Writes and directory listings always go to the new bucket, so anything your application saves after cutover lands directly on Laravel Cloud. Existence and metadata checks, such as `Storage::exists` and `Storage::size`, consult either disk without triggering a copy. By default, a failed promotion (for example, the new bucket is briefly unreachable) doesn't fail the read; Laravel just returns the file from the fallback disk. Set `'throw_on_promotion_failure' => true` on the disk if you'd rather the read fail loudly. Either way, keep an eye on your logs during the migration window: [Laravel Nightwatch](/docs/knowledge-base/nightwatch-on-cloud) surfaces exceptions like these in real time, which helps catch credential or permission issues with either disk early. ## Step 4: Point your application at the read-through disk Update `FILESYSTEM_DISK` to your new read-through disk, and redeploy: ``` FILESYSTEM_DISK=assets ``` From this point on, every file read through `Storage::disk('assets')`, or the default `Storage` facade, transparently pulls from whichever bucket actually has the file, and quietly migrates it to Laravel Cloud along the way. ## Step 5: Speed up the migration (optional) Waiting for real traffic to touch every file can leave rarely accessed files on your old provider indefinitely. To migrate everything up front instead, loop over the fallback disk's contents and read each file through the read-through disk: ```php theme={null} use Illuminate\Support\Facades\Storage; $legacy = Storage::disk('legacy'); $assets = Storage::disk('assets'); foreach ($legacy->allFiles() as $path) { $assets->get($path); } ``` For large buckets, dispatch this as a queued job per file (or per batch of files) instead of running it inline. ## Step 6: Retire the old provider Once every object in your old bucket exists in Laravel Cloud, remove the fallback. Use your storage provider's inventory or compare the object keys in both buckets to confirm the migration is complete: 1. Set `FILESYSTEM_DISK` back to your bucket's disk name (`r2`). 2. Remove the `legacy` and `assets` disk entries from `config/filesystems.php`. 3. Redeploy. 4. Cancel or delete the bucket with your old provider. # How much memory do your queue workers need? Source: https://cloud.laravel.com/docs/knowledge-base/sizing-queue-worker-memory Measure what your queued jobs actually use and choose the right memory size for your managed queue workers. This guide is for Laravel applications. When you create a Laravel Cloud [managed queue](/docs/queues#managed-queues), you choose how much memory each worker receives. Flex workers support between 256 MiB and 2 GiB of memory, while Pro workers support up to 8 GiB. This is the only sizing decision required for a managed queue, and you can adjust the size with each deployment. This guide explains how to measure your jobs' memory usage and choose an appropriate size. Sizing is always a per-queue exercise. Each managed queue processes exactly one Laravel queue name, so you are measuring the jobs that run on that particular queue: the jobs your application dispatches to it with `->onQueue(...)`, or every job dispatched without an explicit queue name if it is the environment's [default queue](/docs/queues#setting-a-default-queue). Keep that boundary in mind throughout this guide, especially once you have more than one queue. ## Start with your jobs A worker's memory needs are driven by what your job's `handle` method loads into memory while it runs. Job payloads are capped at 1 MiB, so the payload itself is never the problem; the question is what the job pulls in while doing its work. Typical Laravel jobs, such as sending mail, firing notifications, processing webhooks, and updating records, use well under 100 MB, and the default **256 MiB** size handles them comfortably. Jobs may require a larger size when they hydrate large sets of Eloquent models, read entire files into memory, generate exports or reports, manipulate images and video, or run machine learning inference. ## Size for the largest job on the queue Each worker processes one job at a time, and every job dispatched to a queue runs on a worker of that queue's size. The memory size therefore needs to fit the hungriest job that will ever cross the queue, not the average one. When a job needs more memory than its worker has, it runs out of memory (often abbreviated "OOM"). The job typically fails with a PHP fatal error reporting that the allowed memory size was exhausted. The worker then restarts, and the job is redelivered to another worker. Redelivery does not resolve an undersized queue: the job fails on every attempt until it exhausts its retries and appears in [failed jobs](/docs/queues#observability). An occasional restart is harmless, but a job class that consistently runs out of memory requires a larger queue size or its own queue. ## Measure locally For a quick estimate, run your worker in verbose mode while dispatching jobs locally: ```shell theme={null} php artisan queue:work -v ``` In verbose mode, each completed job's output line includes the worker's current memory usage. This reflects the worker process as a whole rather than the individual job, but it gives you an immediate ballpark. By default, a worker only processes the default queue. If you are sizing another queue, dispatch your test jobs to that queue and start the worker with the matching option, such as `php artisan queue:work -v --queue=invoices`. Without the `--queue` option, you may measure the wrong jobs. For a true per-job reading, register a temporary listener in your `AppServiceProvider`'s `boot` method: ```php theme={null} use Illuminate\Queue\Events\JobAttempted; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Log; Event::listen(function (JobAttempted $event) { Log::info('Job peak memory', [ 'job' => $event->job->resolveName(), 'peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 1), ]); }); ``` The queue worker resets PHP's peak memory counter between jobs, so each log entry reflects the job's peak memory usage. The `JobAttempted` event fires whether the job succeeds or fails. Dispatch a realistic sample of your heaviest jobs using realistic file sizes and production-like data volumes. After the worker processes them, review the peaks in your log. Dispatch into a genuinely local environment. If your `QUEUE_CONNECTION`, database, mail driver, or API credentials point at shared or production services, a memory test can drop jobs onto a real queue, send real emails, or hit live APIs. Check your `.env` first and point anything live at a local or sandbox equivalent (for example, `MAIL_MAILER=log`). Choose the smallest size that provides roughly 30% headroom above your largest peak. This headroom accommodates day-to-day variations in your data and the memory reserved for the worker runtime. ## Let an AI agent measure it for you An AI coding agent can perform the measurement for you. It can identify the queue you are sizing, verify that your local environment is safe, find and run the relevant jobs locally, and recommend a size or queue split. Help me choose a memory size for a Laravel Cloud managed queue by measuring what my queued jobs actually use. 1. First, ask me which queue I am sizing. On Laravel Cloud, each managed queue processes exactly one queue name, so we are measuring only the jobs that run on that queue. If it is my environment's default queue, that means every job dispatched without an explicit queue name. 2. Work out which of my job classes run on that queue: dispatches using `->onQueue(...)`, jobs that set their queue in the constructor, and queued listeners, mailables, and notifications (including `viaQueue`), plus jobs that fall through to the default. Flag the ones most likely to use significant memory, such as jobs that load many models, process files, or build exports and reports. 3. Before anything is dispatched, run a safety check on my local setup and report what you find: confirm `APP_ENV` is local; confirm `QUEUE_CONNECTION` uses a driver on this machine (such as `database`, or `redis` pointing at localhost) rather than a remote or production queue; and review my `.env` for live services the sampled jobs would touch, such as a remote database, a real mail driver, or live payment and API keys. Point anything risky at a local or sandbox equivalent (for example `MAIL_MAILER=log`) and tell me what you changed. If my queue connection is `sync`, switch it to `database` for the test. If anything still looks like it could reach production, stop and ask me before continuing. 4. Register a temporary event listener in app/Providers/AppServiceProvider.php that listens for `Illuminate\Queue\Events\JobAttempted` and logs each job's class name and peak memory in MB using `round(memory_get_peak_usage(true) / 1024 / 1024, 1)`. The worker resets the peak between jobs, so each reading is per-job. 5. Once the safety check passes, help me dispatch a representative sample of those jobs locally with realistic data, then process them with `php artisan queue:work --stop-when-empty`, passing `--queue=` with the queue name from step 1 so we process the right jobs. 6. Present a table of peak memory per job class, then recommend the smallest Laravel Cloud managed queue size that leaves at least 30% headroom above the highest peak. The sizes are 256 MiB, 512 MiB, 1 GiB, and 2 GiB on the Flex class, with 4 GiB and 8 GiB available on Pro. If one job class peaks far above the rest, also recommend splitting it onto its own managed queue, with a suggested size for each of the two queues. 7. When we're finished, remove the temporary listener and revert any `.env` changes we made for the test. ## Verify on Cloud Local measurements provide a useful starting point, while production data confirms whether your queue is sized appropriately. Every environment with managed queues has a **Queues** tab with a **Memory** chart that displays peak worker memory usage over time. If peaks approach the top of the chart, increase the queue size. If they remain well below the limit, you may be able to decrease it. In a development or staging environment, you may start small, dispatch representative work, and increase the size if jobs fail. In production, start with more memory than you expect to need, run a full business cycle that includes scheduled work such as nightly imports or reports, and then reduce the size while keeping a comfortable margin below the limit. Workers are billed per second while running, so temporarily allocating additional memory typically costs less than diagnosing out-of-memory failures after launch. The signals of an undersized queue are a "Managed queue crashed and restarted" notification, fatal errors in your logs reporting exhausted memory, or jobs exhausting their retries without a clear exception. ## Split queues by memory profile If nine of your job classes peak under 100 MB and one PDF-processing job needs 2 GiB, a single queue forces every job onto 2 GiB workers. Instead, create a smaller queue for most jobs and a larger queue for the resource-intensive job, which you may dispatch using `->onQueue('heavy')`. Each managed queue is sized independently, so most of your work runs on smaller, less expensive workers. The larger workers are billed only while the resource-intensive job runs. Before allocating more memory, consider reducing the job's memory usage. Process large datasets with chunked queries or `LazyCollection` instead of loading entire tables, stream files to [object storage](/docs/resources/object-storage) instead of reading them entirely into memory, or split one large job into several smaller jobs that can run across multiple workers. Each worker's temporary disk scales with its memory (512 MiB of disk per 1 GiB of memory), so a job that stages large files may need a larger size for disk capacity rather than memory. See [Filesystem](/docs/queues#filesystem) for details. For per-job timing and failure analytics across your entire application, consider pairing managed queues with [Laravel Nightwatch](https://nightwatch.laravel.com). # SQLite Support Source: https://cloud.laravel.com/docs/knowledge-base/sqlite Learn why SQLite is not supported on Laravel Cloud, which databases we recommend, and how to migrate from SQLite to PostgreSQL or MySQL. While SQLite is a popular option for development and lightweight applications, **it is not supported in Laravel Cloud production environments**. This is because Laravel Cloud environments are [ephemeral](../environments#filesystem), meaning the filesystem resets across deployments, reboots, and infrastructure migrations. Since SQLite stores data in a single file on disk (often `*.sqlite`, `*.db`, or a path you configure in `DB_DATABASE`), any changes are lost whenever your application is redeployed, sleeps and wakes, or is moved between hosts. We recommend [**Laravel Serverless Postgres**](/docs/resources/databases/postgres) or [**Laravel MySQL**](/docs/resources/databases/laravel-mysql). Both keep your data across deployments, and Serverless Postgres and Laravel MySQL Flex sizes scale to zero when idle. ## Migrating from SQLite to PostgreSQL or MySQL When you deploy to Laravel Cloud, you need a hosted database such as [Laravel Serverless Postgres](/docs/resources/databases/postgres) (Neon) or [Laravel MySQL](/docs/resources/databases/laravel-mysql). If your app currently uses SQLite, migrate your schema and data using one of the paths below. ### SQLite to PostgreSQL You can move your data to Laravel Serverless Postgres with [pgloader](https://pgloader.io/) or with `psql`. pgloader converts and loads your SQLite file in a single step, so it is the simpler option. Before you start, check pgloader's release notes to confirm it supports your database's Postgres version. If it doesn't, [dump and import with psql](#with-psql) instead. Both options need your database's connection details. To find them, navigate to your organization's **Resources** page, click the **...** icon next to your database, and click **View credentials**. Serverless Postgres requires SSL, so every connection string must include `sslmode=require`. #### With pgloader Run pgloader with the absolute path to your SQLite file and your Serverless Postgres connection string. pgloader creates the tables, converts SQLite's column types to Postgres types, and copies your data: ```bash theme={null} pgloader sqlite:///absolute/path/to/database.sqlite "postgresql://user:password@ep-example-123456.us-east-2.pg.laravel.cloud/dbname?sslmode=require" ``` See [pgloader's SQLite reference](https://pgloader.readthedocs.io/en/latest/ref/sqlite.html) for additional options. Confirm that row counts match across all tables, foreign keys and unique constraints behave as expected, and your application runs against the new database without query errors. #### With psql From your project directory, dump the database to SQL: ```bash theme={null} sqlite3 database.sqlite .dump > dump.sql ``` PostgreSQL uses different syntax than SQLite. Edit `dump.sql` as needed: * Remove or replace `BEGIN TRANSACTION` and `COMMIT`. * Replace `INTEGER PRIMARY KEY AUTOINCREMENT` with `SERIAL PRIMARY KEY` or `BIGSERIAL PRIMARY KEY`. * Replace `BLOB` with `BYTEA`. * Remove all `PRAGMA` statements. * Replace `TEXT` columns that store dates with `TIMESTAMP` if you want PostgreSQL-native date handling. ```bash theme={null} psql "postgresql://user:password@ep-example-123456.us-east-2.pg.laravel.cloud/dbname?sslmode=require" < dump.sql ``` Confirm that row counts match across all tables, foreign keys and unique constraints behave as expected, and your application runs against the new database without query errors. ### SQLite to MySQL 8.4 ```bash theme={null} sqlite3 your_database.db .dump > dump.sql ``` Edit `dump.sql` for MySQL compatibility: * Translate SQLite’s `INTEGER PRIMARY KEY AUTOINCREMENT` pattern into a MySQL integer primary key column that uses `AUTO_INCREMENT`. * Replace `TEXT` with `LONGTEXT` or `VARCHAR(n)` as appropriate for your columns. * Remove all `PRAGMA` statements. * Change double-quoted identifiers (for example, `"column"`) to backticks (for example, `` `column` ``). * Replace `BEGIN TRANSACTION` with `START TRANSACTION`. * Keep `BLOB` as `BLOB`. * Booleans: SQLite stores booleans as `0`/`1` integers; MySQL’s `TINYINT(1)` behaves the same way. * `utf8mb4` is the default character set for new databases on MySQL 8.4 in most configurations, so you often do not need to set it explicitly. ```bash theme={null} mysql -u user -p target_db < dump.sql ``` Confirm that row counts match across all tables, foreign keys and unique constraints behave as expected, and your application runs against the new database without query errors. ### Before you go live * Run through the migration on a **staging** environment first. * For MySQL, the [`sqlite3-to-mysql`](https://pypi.org/project/sqlite3-to-mysql/) package (`pip install sqlite3-to-mysql`) can automate dialect conversion instead of editing `dump.sql` by hand. * SQLite is permissive about types; PostgreSQL and MySQL are stricter, so invalid data may only surface after you migrate. * Foreign keys are not always enforced in SQLite (for example, when `PRAGMA foreign_keys` is off). Your target database will enforce them, which can reveal existing data integrity problems. # Deploy Statamic on Laravel Cloud Source: https://cloud.laravel.com/docs/knowledge-base/statamic-on-cloud Deploy a Statamic site on Laravel Cloud, keep content and assets persistent, and serve pages from Statamic's static cache. This guide is for Laravel applications that use Statamic. [Statamic](https://statamic.com) is a content management system built on Laravel, so it deploys to Laravel Cloud like any other Laravel application. However, Statamic stores its content as flat files by default, and Cloud environments have an [ephemeral filesystem](/docs/environments#filesystem). This guide walks through the choices you should make before going live so your content, assets, and cache behave as expected. ## Decide where your content lives Each deployment resets your environment's filesystem, and each replica of your App cluster has its own filesystem. Any entry, global, navigation, or user that is saved to disk through the Statamic control panel in production will be lost on the next deployment and will not be visible to other replicas. You have two options: * **Edit content locally.** Treat production as read-only. Your team edits content on their local machines, commits the flat files to your repository, and pushes to deploy. This keeps your content in version control and works well for sites that change infrequently. * **Store content in a database.** If your team edits content through the control panel in production, store it in a [Laravel MySQL](/docs/resources/databases/laravel-mysql) or [Postgres](/docs/resources/databases/postgres) database using Statamic's [Eloquent driver](https://statamic.dev/tips/storing-content-in-a-database). To use the Eloquent driver, install it locally and follow the prompts to choose which repositories (such as entries, globals, and navigation) should move to the database: ```bash theme={null} composer require statamic/eloquent-driver php please install:eloquent-driver ``` Commit the generated migrations and configuration, attach a database to your environment, and add `php artisan migrate --force` to your environment's [deploy commands](/docs/environments#deploy-commands). Statamic users are stored as files by default as well. If anyone signs in to the control panel in production, [store your users in the database](https://statamic.dev/tips/storing-users-in-a-database) so accounts and password changes persist. ## Store assets in object storage Files uploaded to a Statamic asset container are written to the container's filesystem disk. To keep uploads across deployments and replicas, create a [Laravel Object Storage](/docs/resources/object-storage) bucket and attach it to your environment. Cloud injects the S3-compatible connection variables for the bucket's disk automatically. Next, point your asset container at the bucket's [disk name](/docs/resources/object-storage#bucket-disk-names). For example, if you named the disk `assets`, update your container's YAML file: ```yaml content/assets/assets.yaml theme={null} title: Assets disk: assets ``` If you use a public bucket, copy its `AWS_URL` from the bucket settings page into your environment variables so Statamic can generate public URLs for your assets. ## Refresh the Stache on deploy Statamic indexes your content in a cache called the Stache. If your content lives in your repository, refresh the Stache after each deployment so new and changed files are picked up: ```bash theme={null} php please stache:refresh ``` Add this to your environment's [deploy commands](/docs/environments#deploy-commands). Deploy commands don't persist filesystem changes, so attach a [cache](/docs/resources/caches/valkey) to your environment and use it as your application's cache store. The Stache is then stored in the cache, where every replica can read it. ## Enable static caching Statamic's [static caching](https://statamic.dev/static-caching) serves pre-rendered pages instead of building each page on every request. Statamic offers two strategies, and the right one depends on how you scale your App cluster. ### Half measure The half measure strategy stores rendered pages in your application's cache store. Requests still reach PHP, but Statamic returns the cached response without rendering the page. When your cache store is a Cloud [cache](/docs/resources/caches/valkey), every replica shares the same cached pages, so this strategy works with [autoscaling](/docs/compute#autoscaling). Set the following environment variable and deploy: ```bash theme={null} STATAMIC_STATIC_CACHING_STRATEGY=half ``` ### Full measure The full measure strategy writes each page as an HTML file to `public/static`. When your application requires `statamic/cms`, Cloud detects it at deploy time and configures NGINX to serve those files directly, so cached pages are returned without reaching PHP. Form submissions and live previews continue to route to your application. You don't need to write any custom NGINX configuration. Set the following environment variable and deploy: ```bash theme={null} STATAMIC_STATIC_CACHING_STRATEGY=full ``` The full measure cache lives on each instance's local filesystem and is cleared on each deployment. Statamic only invalidates the cache on the instance that handled a content change, so additional replicas would keep serving stale pages. When using the full measure strategy, set your App cluster's [autoscaling strategy](/docs/compute#autoscaling) to **None** and scale vertically by choosing a larger instance size instead of adding replicas. If your site needs to scale horizontally, use the [half measure](#half-measure) strategy instead. ## Monitor your site Once your site is live, [Laravel Nightwatch](https://nightwatch.laravel.com) gives you visibility into slow requests, exceptions, queued jobs, and cache hit rates, which is useful for confirming that static caching is doing its job. You can [connect Nightwatch to your environment](/docs/environments#nightwatch-integration) directly from the Cloud dashboard. ## Frequently asked questions **Do I need Statamic Pro to deploy on Cloud?** No. Statamic Solo and Pro both run on Cloud. Check [Statamic's pricing page](https://statamic.com/pricing) for features, such as multiple control panel users, that require a Pro license. **Why did my control panel changes disappear after a deployment?** Content saved as flat files in production is written to the ephemeral filesystem and reset on each deployment. Edit content locally and commit it, or [store content in a database](#decide-where-your-content-lives). **Why are some visitors seeing outdated pages?** If you use the full measure strategy with more than one replica, only the instance that handled a content change clears its cache. Set your App cluster's autoscaling strategy to **None**, or switch to the [half measure](#half-measure) strategy. **Does static caching affect applications that don't use Statamic?** No. Cloud only configures NGINX for static caching when your application requires `statamic/cms`. # Upgrading from MySQL 8.0 to MySQL 8.4 Source: https://cloud.laravel.com/docs/knowledge-base/upgrade-mysql-to-84 Learn how to prepare for and perform the upgrade from MySQL 8.0 to MySQL 8.4 on Laravel Cloud. MySQL 8.0 is entering end-of-life in April 2026. We recommend upgrading all Laravel MySQL 8.0 databases to 8.4 as soon as possible. Although Laravel Cloud makes this incredibly easy, **the upgrade is irreversible**, so take a few minutes to prepare before starting. ## Before you upgrade ### 1. Back up your database Before you do anything, create a manual backup of your database. If something goes wrong, this is your only way to recover. 1. Go to **Organization > Resources > Databases**. 2. Click your Laravel MySQL 8.0 database cluster. 3. Find the **Backups** section on the cluster page. 4. Click **New backup**. 5. Give your backup a name and an optional description, then click **Create backup**. Learn more about [Laravel MySQL backups](/docs/resources/databases/laravel-mysql#database-backups). ### 2. Review core changes between 8.0 and 8.4 Most applications will upgrade without issues, but check the following: **Foreign key strictness.** Foreign key constraints now require a unique key on the parent table's referenced column, not just any index. If your schema has foreign keys referencing non-unique indexes, the upgrade will fail. Check your schema and ensure all referenced columns have a unique key or primary key. **New reserved keywords.** MySQL 8.4 reserves several new words, including `MANUAL`, `PARALLEL`, `QUALIFY`, and `TABLESAMPLE`. If you use any of these as unquoted table or column names, queries will break. Either quote or rename those identifiers. **`FLOAT`/`DOUBLE` with `AUTO_INCREMENT`.** This was deprecated in 8.0 and is fully removed in 8.4. If any of your tables have a column matching this combination, the upgrade will fail. Check with: ```sql theme={null} SELECT table_schema, table_name, column_name, data_type FROM information_schema.columns WHERE extra LIKE '%auto_increment%' AND data_type IN ('float', 'double'); ``` If you get results, convert those columns to an integer type (e.g. `BIGINT`) before proceeding. For the complete list of changes, see the [MySQL 8.4 upgrade documentation](https://dev.mysql.com/doc/refman/8.4/en/upgrading-from-previous-series.html). ## Performing the upgrade ### 3. Run the upgrade Upgrading to MySQL 8.4 is irreversible. Laravel Cloud makes upgrading your database easy. 1. Go to **Organization > Resources > Databases** 2. Find your Laravel MySQL 8.0 database 3. Click "Upgrade" on the yellow banner below the database 4. Confirm your upgrade The process takes up to a few minutes. **Your database will be briefly unavailable during this time**. We recommend doing this during a low-traffic window. ### 4. Verify your application Once the upgrade completes, confirm that your application is connecting and behaving normally. ## After the upgrade ### 5. Delete your backup (optional) Once you're confident everything is working, you can delete the backup from step 1 to free up storage. 1. Go to **Organization > Resources > Databases**. 2. Click your database cluster (now on 8.4). 3. Find the **Backups** section on the cluster page. 4. Click **...** next to your manual backup and select **Delete**. # Using Yarn, PNPM, or Bun Source: https://cloud.laravel.com/docs/knowledge-base/using-yarn-bun-pnpm Learn how to use PNPM, Yarn, or Bun with Laravel Cloud and compare package managers. Laravel Cloud installs and runs `npm` by default during deployments. However, if you prefer to use an alternative JavaScript package manager like **Yarn**, **Bun**, or **PNPM**, you can do so by customizing your build commands. For Laravel and Symfony applications, Laravel Cloud doesn't install these tools for you, but you can install them in your build commands. JavaScript applications, such as Next.js, Nuxt, and TanStack Start, can run on the Bun runtime directly. Laravel Cloud detects it automatically when your repository contains a `bun.lock`, `bun.lockb`, or `bunfig.toml` file. See [Runtimes](/docs/runtimes#node-js-bun-and-deno) for details. If you plan to use a different JavaScript package manager via the examples below, be sure to remove or comment out the default `npm` commands in your build commands before adding the custom commands. #### Example: Using Bun If you would like to use Bun instead of npm, you can override the default build command in your site’s settings with the following: ```bash theme={null} npm install -g bun bun install bun run build ``` #### Example: Using Yarn To use Yarn instead of npm: ```bash theme={null} npm install -g yarn yarn install yarn run build ``` #### Example: Using PNPM To use PNPM instead of npm: ```bash theme={null} npm install -g pnpm pnpm install pnpm run build ``` #### Approving PNPM build scripts PNPM blocks `postinstall` and other build scripts for dependencies it doesn't recognize, so packages with native binaries (for example, `esbuild` or `sharp`) may silently fail to build. Watch for an "Ignored build scripts" warning in your build log. Since Laravel Cloud's build step is non-interactive, approve these scripts locally first, then commit the resulting configuration so the approval is already in place when Cloud builds your application: ```bash theme={null} pnpm approve-builds ``` On PNPM 11 and later, this writes an `allowBuilds` map to `pnpm-workspace.yaml`. On PNPM 9 and 10, it writes an `onlyBuiltDependencies` array to the `pnpm` key in `package.json` instead. Either file should be committed to your repository. A `.npmrc` with `auto-install-peers` or `node-linker=hoisted` does not approve build scripts and won't fix this; use `pnpm approve-builds` instead. # Logs Source: https://cloud.laravel.com/docs/logs Learn how to view, search, and filter Laravel Cloud application and access logs. ## Introduction Open the **Logs** tab under **Monitoring** in any environment to view and search your application's logs. When viewing your logs, you may filter logs based on type: * **Application logs:** log entries written by your application, either manually or when the application encounters an unhandled exception. * **Access logs:** log entries automatically generated by Laravel Cloud when a request is received by your application. ## Log retention Laravel Cloud prioritizes your most recent logs and will eventually delete older logs when they exceed your plan's retention period or storage quota allowance (whichever comes first). Log retention periods vary by plan. See the [Plans feature table](/docs/pricing#plans) for details about log and metrics retention. ## Forwarding logs To forward an environment's logs to an external destination, configure a log drain. See [Log Drains](/docs/services/log-drains/overview) for supported destinations, setup, and billing. # Migrate from Heroku Source: https://cloud.laravel.com/docs/migrate-from-heroku Migrate your Laravel application from Heroku to Laravel Cloud with step-by-step deployment guidance. This guide is for Laravel applications. Learn how to migrate your application from Heroku to Laravel Cloud Heroku is a general-purpose PaaS that many Laravel teams have relied on over the years, but it requires manual PHP configuration, buildpack management, and Procfiles that add unnecessary complexity. Laravel Cloud provides a simpler operational model, framework-aware defaults, and more predictable costs without boilerplate setup required. ### How to migrate If you're running applications on Heroku, the migration process focuses on replacing Heroku-specific concepts, such as Procfiles, buildpacks, dynos, and add-ons, with Laravel Cloud equivalents. The [migration guide](https://laravel.com/cloud/migrate-heroku-cloud) walks you through exporting your Postgres database, provisioning your Laravel Cloud infrastructure, and switching your DNS without any downtime to your existing application. # Migrate from Vapor Source: https://cloud.laravel.com/docs/migrating-from-vapor Learn how to migrate your application from Laravel Vapor to Laravel Cloud This guide is for Laravel applications. While Vapor and Cloud serve similar use cases, Laravel Cloud provides a simpler operational model and a more predictable runtime environment. Many teams migrate from Vapor to Cloud to reduce infrastructure complexity while keeping the same Laravel application. ## How to migrate If you’re running applications on Laravel Vapor, the migration process focuses on mapping your existing configuration and deployment workflows to Laravel Cloud equivalents. The [migration guide](https://cloud.laravel.com/migration-vapor-cloud) explains the benefits of migrating and walks through the required changes. # Monorepos Source: https://cloud.laravel.com/docs/monorepos Deploy applications from a monorepo on Laravel Cloud. ## Introduction Laravel Cloud includes first-class monorepo support. When you create a new application, Cloud analyzes your repository and automatically detects whether it contains a single or multiple applications. ### How it works If Cloud does not detect a monorepo structure, you proceed through the standard application creation flow without any additional steps. If Cloud detects a monorepo, it presents the top-level directories in your repository, allowing you to select the one containing your application. Cloud uses that directory as the root for all build and runtime operations such as commands and background processes. All directories in your repository are accessible during the build, so your application can reference shared packages or sibling directories if needed. Only the selected application directory is deployed, which is why all commands and processes are scoped to it at runtime. ### Deploying multiple applications from the same monorepo If your monorepo contains more than one application, such as a frontend and a backend, you'll need to create a separate application in Laravel Cloud for each one. Attach the same repository to each application, then select a different root directory during setup so Cloud knows which part of the repository to deploy. Each application you create is a fully independent Cloud resource with its own environment variables, instances, scaling settings, domains, and attached services, even though they share a single repository. Because Cloud is framework-aware, it may expose different configuration options depending on each application's runtime. Deploying each application separately allows them to be sized and scaled independently. Your frontend, backend, and other applications often have very different traffic patterns and resource needs, and keeping them as separate applications means you can size, scale, and deploy each one according to its own demands rather than treating them as a single unit. # Laravel Cloud Network Source: https://cloud.laravel.com/docs/network Learn how Laravel Cloud networking works, including edge security, caching, WAF, rate limiting, and custom network settings. ## Introduction Laravel Cloud manages all aspects of networking to provide enterprise-grade speed, security, and scalability for every application. There are two main layers to the Cloud's networking infrastructure: the Cloud Edge Network and the Cloud Compute Network. Private Cloud customers with a dedicated edge network have access to additional networking features including custom rules, cache rules, and private connections to AWS resources. See [Dedicated edge network](/docs/private-cloud/edge-network) and [Private networking](/docs/private-cloud/private-networking) in the Private Cloud documentation. ## Cloud edge network Laravel Cloud has partnered with [Cloudflare](https://cloudflare.com) to offer every application globally distributed caching and network security at the edge. Incoming HTTP requests are first routed to the nearest edge region (335 cities around the world), pass through DDoS mitigation and Web Application Firewall (WAF) security layers, and are either returned from the cache (if available) or passed on to the Cloud Compute Network to be routed to your application's compute cluster. ### Cache control An important function of the Cloud Edge Network is caching your application's static assets. This has two key benefits: it reduces the number of requests that your application's compute needs to handle and it decreases latency for your users. Laravel Cloud optimizes your CDN cache through a two-step approach. First, Cloud uses a long cache lifespan to ensure your static assets are served at the edge as much as possible. Second, Cloud clears the CDN cache automatically on every deployment to ensure that no stale files accidentally remain in the cache. Combined, these two steps offer an efficient and safe approach to CDN caching. By default, Laravel Cloud caches files with the following extensions: `7Z`, `APK`, `AVI`, `AVIF`, `BIN`, `BMP`, `BZ2`, `CLASS`, `CSS`, `CSV`, `DMG`, `DOC`, `DOCX`, `EJS`, `EOT`, `EPS`, `EXE`, `FLAC`, `GIF`, `GZ`, `ICO`, `ISO`, `JAR`, `JPEG`, `JPG`, `JS`, `MID`, `MIDI`, `MKV`, `MP3`, `MP4`, `OGG`, `OTF`, `PDF`, `PICT`, `PLS`, `PNG`, `PPT`, `PPTX`, `PS`, `RAR`, `SVG`, `SVGZ`, `SWF`, `TAR`, `TIF`, `TIFF`, `TTF`, `WEBM`, `WEBP`, `WOFF`, `WOFF2`, `XLS`, `XLSX`, `ZIP`, `ZST` When a `Cache-Control` directive or `Expires` header is not explicitly set, Laravel Cloud will use the HTTP status code to determine the cache duration. | HTTP Status Code | Default TTL | | - | - | | 200, 206, 301 | 120m | | 302, 303 | 20m | | 404, 410 | 3m | All other status codes are not cached by default. You are free to override the default cache rules by setting your own `Cache-Control` and `Expires` headers in your application code. Laravel Cloud will respect these headers and cache your assets according to the rules you set. Certain headers set by your application can prevent Laravel Cloud from caching a response. * The `Set-Cookie` header will prevent caching. * The `Authorization` header will prevent caching (unless a `must-revalidate`, `public`, or `s-maxage` header is also present). To reduce the risk of stale files being served from the cache, Laravel Cloud enables the "Purge edge cache on deploy" setting for your environment by default. You can disable this setting by clicking on the "Edge network" card from your environment's canvas. From there, you can also manually purge the cache or even bypass the cache entirely. Bypassing the cache will result in all requests being sent to your application, which may increase latency and load on your compute cluster. This is not recommended unless you are debugging a specific issue. ### Response rules Laravel Cloud allows you to easily configure a number of security headers that will be set on every response. You can modify the defaults by clicking on the "Edge network" card from your environment's canvas and selecting the desired option. You can also override the default headers by setting them directly in your application code. #### X-Frame-Options By default, Laravel Cloud will set an `X-Frame-Options: DENY` header. This prevents certain types of attacks that can occur if an application is loaded from an iframe. If your application has a use case for allowing iframes, you can change the header value to `SAMEORIGIN` or you can unset it entirely by clicking "Edge network" from the environment's canvas. #### X-Content-Type-Options By default, Laravel Cloud will set an `X-Content-Type-Options: nosniff` header. This prevents browsers from interpreting files as a different MIME type than what is specified in the `Content-Type` header. This is a security measure to prevent attacks based on MIME-type confusion. If your application has a use case for allowing browsers to interpret files as a different MIME type, you can unset the header entirely by clicking "Edge network" from the environment's canvas and selecting "None". If you select the "None" option for the `X-Content-Type-Options` header, your application can override the default and set a `nosniff` value at the route level. However, the the opposite is not true: if you select the `nosniff` option, your application cannot unset the value. #### Strict-Transport-Security HSTS is disabled by default but can be enabled with a simple toggle. When enabled, Laravel Cloud will set a `Strict-Transport-Security` header with a max-age of 31536000 seconds (1 year - customizable). This header is used to enforce secure (HTTPS) connections to the server. You can also optionally enable the `includeSubDomains` and `preload` directives. The `includeSubDomains` directive applies the HSTS policy to all subdomains of your application, while the `preload` directive allows your domain to be included in browsers' HSTS preload lists. This means that browsers will automatically enforce HTTPS for your domain and its subdomains, even before the first request is made. Make sure you understand the implications of these directives before enabling them, as it can be difficult to remove once set due to browser caching. #### Markdown for Agents Markdown for Agents enables real-time HTML to Markdown conversion at the edge for AI agents and crawlers. When enabled, AI systems can request your application's pages in Markdown format by including `Accept: text/markdown` in their request headers. Cloudflare's network will automatically convert the HTML response to Markdown before serving it to the client. Markdown's explicit structure is ideal for AI processing, resulting in better comprehension while significantly reducing token usage compared to raw HTML. When a response is converted, the following headers are included: * **`x-markdown-tokens`**: An estimated token count of the Markdown document, useful for calculating context window sizes or chunking strategies. * **`content-signal`**: Indicates AI usage permissions following the [Content Signals](https://contentsignals.org/) framework. By default, this is set to `ai-train=yes, search=yes, ai-input=yes`. You can enable or disable Markdown for Agents by clicking on the "Edge network" card from your environment's canvas and toggling the setting in the "Response" section. The origin response must not exceed 2 MB, and only HTML content is eligible for conversion. For more information, refer to [Cloudflare's Markdown for Agents documentation](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/). ### X-Robots-Tag Since Laravel Cloud domains are often used for testing and staging purposes, a `X-Robots-Tag: noindex, nofollow` header is automatically set on all `*.laravel.cloud` domains so that they are not indexed by search engines. To remove this header, you should configure a custom domain for your application. The header will not be set for custom domains. ## Cloud compute network Requests that need to be processed by your application will be routed to the Compute Network in the AWS region assigned to your Laravel Cloud application. The Cloud Compute Network is built for security and scale. Your applications run in private networks and are only made publicly accessible via the Cloud Edge Network. Compute clusters are distributed across multiple availability zones (AZs) to ensure regions remain stable and recover quickly from any interruptions in a single zone. Compute Network traffic is also intelligently load balanced across all instances in your compute cluster as you horizontally scale up or down. ## Web application firewall The Web Application Firewall (WAF) provides advanced protection for your Laravel Cloud applications by filtering and monitoring HTTP traffic between your application and the Internet. All traffic routed through Laravel Cloud's edge network, via the default `app.laravel.cloud` hostname or a custom domain proxied through Cloudflare, runs behind Cloudflare's [OWASP Core Ruleset](https://developers.cloudflare.com/waf/managed-rules/reference/owasp-core-ruleset/), giving every environment managed protection that maps to the OWASP Top 10 before traffic ever reaches your app. Cloudflare's managed rules can flag server-to-server callbacks that use a default library `User-Agent` (for example, Python's `urllib`). If you're migrating from a platform that didn't sit behind Cloudflare (for example, Laravel Vapor, which fronts applications with CloudFront) and an inbound webhook starts failing with no application-level error, set a descriptive `User-Agent` header on the sending request rather than relying on the library default. ### Bot categories Bot categories allow you to present a JavaScript challenge to clients identified as specific types of automated traffic. Visitors matching your selected bot categories will see a challenge before they can access your application. Categories include, but are not limited to, AI crawlers, AI assistants, advertising and marketing bots, aggregators, search engine optimization bots, social media marketing bots, and monitoring tools. You can configure bot categories by clicking on the "Edge network" card from your environment's canvas and selecting the "Web Application Firewall" tab. Bot categories are available for [Business plan](/docs/pricing) customers. ### Rate limiting Rate limiting protects your application from abuse by controlling how many requests a client can make within a given time period. #### Basic rate limiting When enabled, Laravel Cloud will intercept requests from any IP address that exceeds 100 requests per minute. You can choose from three actions: * **Challenge**: Present a challenge (CAPTCHA or Turnstile) to the IP address. The challenge will be shown for 5 minutes. * **Throttle**: Block new requests from the IP address for 5 minutes. * **Ban**: Block all requests from the IP address for 5 minutes. To configure basic rate limiting, click on the "Edge network" card from your environment's canvas and select the "Web Application Firewall" tab. Basic rate limiting is available for [Growth and Business plan](/docs/pricing) customers. #### Advanced rate limiting Advanced rate limiting includes all basic rate limiting features plus additional customization: * **Customizable threshold**: Set your own requests per minute threshold instead of the default 100 rpm. * **Block repeated 4xx responses**: Block clients that send more than 30 unauthorized / error requests per minute (401, 403, 404) for 10 minutes. * **Block excess 429 responses**: Block clients that continue sending traffic after receiving more than 5 rate limit responses from your application. The block will last for 10 minutes. Advanced rate limiting is available for [Business plan](/docs/pricing) customers. ### Under attack mode If your application is experiencing a large-scale attack or suspicious traffic spikes, you can enable "Under Attack Mode" in the Edge network settings for your environment. When activated: * All incoming traffic to your environment is filtered through additional Cloudflare security checks designed to mitigate layer 7 DDoS attacks. * Visitors will see an interstitial "Checking your browser before accessing..." page and must pass a JavaScript challenge, which typically takes no more than 5 seconds. * Validated users are allowed through, while suspicious or automated traffic is blocked. * Under Attack Mode is intended as a last resort during active threats and may temporarily pause access to your site and impact your site analytics. * This mode will automatically expire after 24 hours to ensure normal access is restored. * Browsers must support JavaScript to pass the challenge; some third-party analytics tools may be affected. Enabling Under Attack Mode may temporarily impact the user experience for legitimate visitors due to the additional security checks. Use this mode only when necessary. ## IP addresses Laravel Cloud applications may make outbound requests from any of the following IP addresses. This information is useful when configuring firewalls, security groups, or allowlists for external services that your application needs to access. If your organization has dedicated compute available from [Private Cloud](/docs/private-cloud), make sure to use the dedicated IP addresses provided during your onboarding instead of the ranges provided below. ### Programmatic access The IP addresses are also available via API for programmatic access: ```bash theme={null} curl https://cloud.laravel.com/api/ip ``` This endpoint returns a JSON object with IP addresses organized by region: ```json theme={null} { "us-east-2": { "ipv4": ["3.140.62.214", "3.139.253.68", ...], "ipv6": ["2600:1f16:e0:8500::/56"] }, "eu-west-2": { "ipv4": ["35.178.113.65", ...], "ipv6": ["2a05:d01c:243:e500::/56"] } } ``` These IP addresses are subject to change. We recommend checking this endpoint regularly or subscribing to our changelog for updates. # Notifications Source: https://cloud.laravel.com/docs/notifications Configure notifications and alerts for Laravel Cloud events. ## Introduction Laravel Cloud makes it easy to stay informed about important events through email and Slack notifications. Email preferences are personal to each team member, while Slack notifications are sent to your organization's connected workspace. Both delivery methods share the same set of notification categories, scoped to your organization, applications, and environments. ## Notification categories Notifications are grouped by the scope they apply to. Each category belongs to one of three scopes: your organization, a specific application, or an individual environment within an application. ### Organization The following categories apply to your organization as a whole: * **Organization updates** – Changes to your organization's settings * **Members** – New and removed members of your organization * **API tokens** – API tokens issued and revoked from your organization * **Applications** – Creation and deletion of applications in your organization * **Resources** – Creation, deletion, and changes to resources * **Resource alerts** – Usage, limits, and health alerts for caches, databases, compute, and WebSockets * **Monthly spend alert** – Alerts at 50%, 80%, 90%, and 100% of your [spending limit](/docs/spending-limits) * **Payments** – Successful and failed payments, or only failed payments ### Application The following categories apply to a specific application: * **Application** – Changes to this application * **Environments** – Creation and deletion of environments in this application * **Automations** – Creation, deletion, and changes to [automations](/docs/scheduled-tasks) ### Environment The following categories may be configured independently for each environment within an application: * **Environment** – Changes to this environment * **Network** – Creation, deletion, and changes to domains * **Cluster alerts** – Alerts when clusters have high CPU or RAM usage, or are crashing * **Deployments** – Successful and failed deployments, or only failed deployments * **Commands** – Successful and failed commands, or only failed commands ## Email notifications Email notifications are configured per user, allowing every team member to subscribe to the events they personally care about across the organizations, applications, and environments they have access to. To configure your email preferences, click your profile picture in the top-right corner of the dashboard, select **Account**, and open the **Notifications** tab. From this page, you may enable email notifications globally, then choose the categories you wish to receive emails about for each of your organizations and applications. ### Organization notifications After selecting an organization from the organization selector, you may enable any of the [organization categories](#organization) you wish to receive emails about. Your preferences are saved per organization, so you can subscribe to different categories for each organization you belong to. ### Application notifications Application preferences are managed independently for each application. After selecting an application, you may enable any of the [application categories](#application) for the application as a whole, as well as the [environment categories](#environment) for each individual environment within that application. By default, you'll receive email notifications for members, API tokens, resource alerts, monthly spend alerts, failed deployments, failed commands, and failed payments. You may adjust these preferences at any time. ## Slack notifications Slack notifications send Laravel Cloud events to channels in your connected Slack workspace, keeping your team informed of activity as it happens. Unlike email, Slack preferences are shared by your team and configured at the organization level. ### Connecting to Slack To get started, open your organization's **Integrations** settings and click **Connect Slack workspace**. A new window will open where you can complete the integration with your Slack workspace. ### Configuring Slack delivery Once your Slack workspace is connected, open your organization's **Notifications** settings and enable Slack notifications. From here, you may control how and where notifications are sent: * **Default channel** – The channel where notifications are sent unless a more specific override applies. * **Overrides** – Send notifications for a specific application to a different channel. You may add as many overrides as you need. * **New environment behavior** – Determines what happens automatically when a new environment is created within an application: * **Notify all** – Enable every notification category for the new environment. * **Defaults** – Apply your application's default notification settings. * **Mute all** – Disable every notification category for the new environment. ### Organization notifications From your organization's **Notifications** settings, you may select which [organization categories](#organization) are sent to your Slack workspace. ### Application notifications Each application has its own Slack notification preferences, configured independently from your organization's notifications. Open your application's **Notifications** tab to select which [application categories](#application) and [environment categories](#environment) are sent to Slack. # Organizations Source: https://cloud.laravel.com/docs/organizations Manage Laravel Cloud organizations, members, permissions, billing, and shared application resources. ## Introduction After registering with Laravel Cloud, you will be assigned to an organization. For new registrations, this will be a brand new organization created just for you; however, if you are invited by another Laravel Cloud user, you will be added to the existing organization you were invited to. In Laravel Cloud, the organization is the top-level entity that owns all applications, environments, and resources such as databases and custom domains. Each organization's member and billing plan configuration is unique, so each organization may configure its own payment method details and preferred pricing plan. ## Organization members You can manage your organization's members from **Settings > Access**. Each member has a role that controls what they can view and manage. See [Roles and permissions](/docs/rbac) for the available roles. ### Inviting new members To invite someone to an organization, navigate to the organization's dashboard and click **Settings > Access**. Then, enter the email of the new user and click "Invite". The invited user will receive an email that will allow them to accept the invitation to join the organization. #### Revoking invitations To revoke an invite, an admin can navigate to your Organization dashboard and click **Settings > Access**. On any rows that show the "Invite Pending" status, click the more "…" button and select "Revoke Invite." ### Removing members To remove a member from an organization, navigate to your Organization dashboard and click **Settings > Access**. On a member row, click the more “…” button and select “Remove Member.” ## Organization billing Each organization's billing plan configuration is unique, so each organization may configure its own payment method details and preferred pricing plan. ### Changing plans Every Laravel Cloud organization must have an active subscription. To upgrade or downgrade your plan, an Admin can navigate to your Organization dashboard and click **Settings > Billing**. Then, click "Change plan," select a new plan, and then click "Update plan." For upgrades, we will issue a one-off invoice immediately for any usage accrued in the current cycle plus the new subscription fee (pro-rated based on days remaining in the current billing cycle). We will then continue to issue monthly invoices on the regular anniversary billing date. For downgrades, you will continue to have access to the higher plan and its features for the rest of the billing cycle. Downgrading plans will result in the loss of access to some features like custom domains and autoscaling. Make sure your applications do not depend on these features before downgrading. ### Canceling subscriptions If you wish to stop using Laravel Cloud, you can cancel an organization's subscription at any time. To cancel an organization's subscription, an Admin can navigate to the organization's dashboard, click **Settings > Billing**, and click "Cancel subscription." Your subscription will continue on the current plan for the rest of your current billing cycle. At the end of the billing cycle, any remaining environment compute, resources, or custom domains that are still active will be terminated. Two days later, your final invoice will be processed. After subscription plan termination, you will still have access to your organization's basic data such as invoices and members, but you will need to resubscribe to a billing plan before deploying or managing additional applications for that organization. ### Billing details To change an organization's billing details, an Admin can navigate to the organization's dashboard and click **Settings > Billing**. Scroll to the "Billing details" section, and make any changes necessary to your "Bill as" type (Individual or Company), "Billing name", "Billing email", "Billing address", or "Payment method". ### Usage and invoices To view information about your organization's current compute, bandwidth, or other resource usage, navigate to your Organization's dashboard and click "Usage" in the navigation bar. From the usage dashboard, you can review your current spend, your plan allowances, usage by application and environment, and resource usage across your organization. ## General settings ### Renaming organizations To rename an organization, navigate to the organization's dashboard and click Settings. On the General tab, edit the Organization Name field. After updating the name, click Save. ### Deleting organizations To delete an organization, navigate to the organization's dashboard and click Settings. Then, on the General tab, click the Delete Organization button. Deleting an organization requires the organization to be current on all outstanding invoices and have no additional usage charges for the current billing period. Deleting an organization is permanently destructive and cannot be undone. All organization member, application, and resource data will be terminated immediately. ## Notifications Connect Laravel Cloud to your Slack workspace to receive notifications about your organization, applications, resources, and more. See [Notifications](/docs/notifications) for detailed setup of Organization notifications. # Preview Environments Source: https://cloud.laravel.com/docs/preview-environments Generate a fully isolated environment for every pull request to safely test changes, share previews, and catch issues before merging.