| name | laravel-cloud-deploy |
| description | Method for provisioning Laravel Cloud environments + resources and enabling deployments safely. THE CARDINAL RULE: never set environment variables for Cloud-provisioned resources — Cloud auto-injects ALL resource config (credentials AND connection selectors like QUEUE_CONNECTION/DB_CONNECTION/CACHE_STORE) into a separate managed env file the app reads; any value you set yourself overwrites/shadows the injected one and breaks the resource (and is easy to get wrong). Use whenever asked to create/provision a Cloud environment, attach resources (DB/Redis/queue/object storage), or restore/enable deploys. Requires the project's .cloud repo config (cloud repo:config) bound first. |
| license | MIT |
| metadata | {"author":"artisan-build","origin":"Generalized from a Laravel Cloud production-env build where manually-set resource env vars overwrote Cloud's auto-injected values (incl. a wrong QUEUE_CONNECTION). Canonical source: brain/skills/laravel-cloud-deploy."} |
Laravel Cloud provisioning & deploy (method)
You are provisioning/configuring a Laravel Cloud environment. This is infrastructure ops, not a feature
build — do it directly, don't spawn a build loop. Cloud's credential model punishes guessing, so follow
this exactly.
⛔ THE CARDINAL RULE — never set env vars for provisioned resources
Laravel Cloud auto-injects all configuration for ATTACHED resources into a separate, managed
environment file the app reads at runtime — and this is NOT just secrets. It includes the connection
selectors too:
- DB:
DB_* and DB_CONNECTION
- Cache/Redis:
REDIS_*, CACHE_STORE, SESSION_DRIVER (where Cloud manages them)
- Object storage:
AWS_* + the S3/bucket config (and FILESYSTEM_DISK where managed)
- Managed queue:
SQS_* and QUEUE_CONNECTION
So when you provision/attach a Cloud resource, set NO environment variable related to it — not the
creds, not the connection selector, nothing. If you set any of these yourself (in .env or as a Cloud
env var), your value OVERWRITES / SHADOWS the injected one — which breaks the resource, and you can
easily set it wrong (real example: setting QUEUE_CONNECTION=sqs when Cloud injects a different
connection name for its managed queue → no jobs process).
The flow is always: provision → attach → let Cloud inject → verify the app reads the injected values.
Never hand-set resource config at any step.
What you MAY set
Only genuinely app-specific config that Cloud does NOT inject and that has nothing to do with a
provisioned resource:
APP_ENV, APP_DEBUG, APP_NAME, APP_URL (let Cloud generate/preserve APP_KEY).
- Pure application knobs (e.g. the settle engine's
REWORK_CHUNK_SIZE, CHEAP_CHUNK_SIZE,
ONLINE_MAX_COMMITS).
- Empty placeholders for THIRD-PARTY creds the human wires later (Slack token, mail/Resend key) — these
are not Cloud-managed resources.
When unsure whether Cloud injects something, DON'T set it. Provision and deploy first, then inspect
what actually got injected; only add a var if it's genuinely missing AND not tied to a managed resource.
Step 0 — precheck the .cloud config (do this FIRST)
Check for a .cloud config in the project folder (produced by cloud repo:config). If it's absent →
STOP and ask the human to run cloud repo:config. The CLI cannot bind org+repo non-interactively;
without it you'll waste effort reverse-engineering tokens and risk targeting the WRONG org. Verify the
bound org is correct, and exclude .cloud/ from git locally (.git/info/exclude).
Step 1 — mirror the existing environment
cloud environment:get <existing-env> --json → read its PHP version, instances, attached resources, and
which vars are injected vs app-set. Mirror that shape for the new env; match the PHP version unless told
otherwise.
Step 2 — create env + provision resources (CLI), attach (often dashboard)
Create the env; provision DB, cache/Redis, managed queue, object storage as needed; attach each
(attach is what triggers injection). Known CLI gaps (≥ v0.5.0) that force the dashboard:
- DB/cache attach —
env:update --database-id/--cache-id silently no-ops headlessly.
- Managed queue create — CLI hardcodes
minReplicas: 1; managed queues must scale to zero → API rejects.
- Bucket → env attach — no CLI flag exists.
Produce a clear dashboard checklist for the human for everything the CLI can't do. The human attaches;
injection follows.
Step 3 — runtime drivers belong in the BUILD, not at deploy
The app's composer deps must already include the drivers the Cloud resources need — aws/aws-sdk-php for
the sqs queue, league/flysystem-aws-s3-v3 for the s3 disk. Add these in the build. (CI/tests pass on
local/sync/array drivers, so a missing production driver stays green until it fails in production.)
Step 4 — enabling deploys (only when explicitly asked)
The deploy-hook URL lives as a repo secret; the deploy GitHub Action calls it on push to main. Restore or
enable that action only when asked. Do NOT enable the deploy hook or flip DNS unless explicitly
instructed — those are usually the human's to control (e.g. cutting over from an old env by DNS).
Step 5 — verify, don't assume
After deploy: confirm the app boots, the injected resource config is present AND correct (queue connects,
Storage::disk('s3') reads/writes, DB migrates), and the runtime (python3 --version, PHP version)
matches expectations. If a value looks wrong, first check whether you set a var that's shadowing an
injected one — and remove yours. (The CLI has no reliable per-key env-var delete → use the dashboard.)
Don'ts
- No env vars for provisioned resources — the cardinal rule, no exceptions.
- No secrets written to stdout or disk; redact resource values (print IDs/names only).
- No deploy-hook or DNS changes unless explicitly told.
- Nothing destructive to existing environments or their data; report before any irreversible step.