Interactive command. At a TTY,
fjall deploy renders a live step
checklist, a change plan, and an approval prompt before anything is applied.Overview
fjall deploy ships one application to AWS: its infrastructure (ECS, Lambda, RDS, Aurora, networking, load balancers) and its container image.
The positional argument is the application name. Tier and domain deploys are separate noun-verb commands.
Prerequisites
- Logged in with
fjall login. - An AWS account connected with
fjall connect. - An active deployment target selected with
fjall target set <name>, unless your organisation has exactly one target.
Usage
service positional to deploy a single service inside a multi-service application.
What each command deploys
Tier deploys
fjall org deploy cascades: organisation, then platform, then domains, then every member account. fjall platform deploy and fjall account deploy never cascade.
Each tier leaf registers only the flags that tier honours. The approval-gate family (--plan, --require-approval, --auto-approve, --approval-token) and the application-scoped build flags are rejected by Commander on tier commands.
-e, --environment on fjall account deploy is a fixed choice list
(production, staging, development, platform, compliance) and stamps
the stage recorded for a standalone account. It is a different flag from
-e, --environment on fjall deploy, which is a free-form build-arg tier
selector. See Options.Domain deploys
fjall domain deploy <name> is the only domain-deploy spelling. Full reference: fjall domain.
Domain-specific semantics:
- A variant record set carries its SetIdentifier in the consent name. Weighted, latency, and failover variants are classified and consented per variant:
--remediate 'www.example.com/A@blue'=recreate. --allow-replaceis not registered on domain deploys. Commander rejects it rather than dropping it silently. Consent to takeover rows with--remediateinstead.- Exit
4means the takeover consent was withheld. Nothing was released and nothing was deployed. See Destructive Changes.
Interactive mode
Run without arguments for a guided deploy:Deploy Organisation, Platform and Accounts?, default Yes). Platform and Account start that single stack’s deploy with no cascade question. The progress screen can still raise a change confirmation, and an environment prompt when no --environment was passed.
Options
Build options
-e, --environment <env> does not select an account, a region, a target,
or the synthesis environment. Its only live effect is choosing which
.env.<stage> file supplies build args. The account comes from the active
target (or --target). The synthesis environment, which decides every removal
policy, is derived from the target account’s own record. See Choosing the
deploy account.Fjall image tags are content-addressed:
<service>-sha-<12 hex chars of the image digest>. Find the tags for an application in its ECR repository (AWS
console or aws ecr list-images). Tags like v1.4.2 are not produced by
Fjall builds and will not resolve.Plan and approval options
Destructive-change and gate options
These satisfy the destruction gate when a deploy would destroy or replace a stateful resource.CI/CD options
Every command node also accepts the agent-output flags
--agent, --budget <level>, --fields <list> and --full. See Agent mode.
Subcommands
Choosing the deploy account
A deploy lands in the active deployment target, an account plus region pair named<accountname>-<regionabbrev>, for example production-use1 or development-euw1.
At deploy time the account resolves through one fail-closed chain:
--target <name>, when present. An unknown name is a hard error listing the valid targets, never a silent fallback.- Otherwise the
activeTargetrecorded in.fjall/local.json. - Otherwise auto-select, when exactly one target exists, or the root account’s profile when there are none.
- Otherwise refuse, listing the candidate targets.
--region overrides the region within the resolved target’s account.
From fjall 38 a named --target resolves from an organisation config that is fresh or inside the five-minute cache TTL. An unreachable API with an expired cache fails with Failed to fetch organisation config: … rather than resolving from an older cached copy. Steps 2 to 4 keep the cache-first read with its stale fallback.
Targets are derived at runtime from your organisation config, fetched from the Fjall API. Accounts, regions, OIDC role ARNs and SSO sessions are never authored by hand in a repository file. See Understanding Profiles.
The synthesis environment is derived from the target account’s own record, not from a flag. The organisation tier resolves to root, and every other account resolves to its recorded stage. The deploy fails closed when that cannot be resolved, because the environment decides every removal policy: production retains data on stack deletion, every other stage destroys it.
What happens during a deploy
1. Pre-flight checks
Fjall validates AWS credentials and permissions, confirms the target exists, checks required dependencies, and probes the stacks for resources deleted outside CloudFormation. A confirmed out-of-band deletion blocks the deploy and points you atfjall drift.
The same pre-flight refuses to start while any target stack is mid-operation or in a state it cannot classify. Each stack is checked in its own region, so an ApiUsEast1Certificates or ApiUsEast1CdnLogging stack busy in us-east-1 blocks the deploy. There is no --force bypass here: unlike fjall destroy, deploying over an in-flight operation is never a recovery.
2. Pre-deployment checklist
A full deploy streams a checklist of four steps, in this order:--deploy-only and --image-tag skip the checklist, SSM secrets validation included.
No build appears in this checklist, for any application: a framework build, and a Payload app’s import map, run before it and outside it. On fjall 39.x, build a Payload app at the project root and deploy with --skip-build, as Build and deploy describes. Without --skip-build, the deploy writes the import map and builds in fjall/<app>, which fails for the layout fjall create app produces.
Missing SSM secrets raise a Missing N of M required SSM secret(s) block and a Deploy anyway? confirmation, defaulting to No.
3. Change plan and approval gate
When nothing changed, the run short-circuits before the gate with anAlready up to date message and applies nothing.
With changes, the approval gate is engaged by default at a TTY. A bordered card renders the plan, then a Yes/No selector defaulting to No.
+ create, ~ update, ± replace, - delete, > read.
--skip-confirmation and --auto-approve drop this prompt. Non-interactive and CI runs show no plan unless you pass --plan or --require-approval.
If the plan would destroy or replace a stateful resource, a further
per-resource consent ceremony runs, with a typed resource name. No flag skips
it. See Destructive Changes.
4. Deployment execution
Fjall creates or updates the CloudFormation stacks, streams per-resource events, handles stack dependencies, and reports errors as they arrive. Concurrent stacks render in a parallel panel.5. Post-deployment
Fjall prints the application’s website URL, next steps, and a version banner. When the deploy replaced the database, it offers to restart the affected services so they reconnect.Examples
Deploy an application
Infrastructure versus code
Plan first, then approve
Deploy plan: <summary> line, one line per change, the destruction ticket and its ticket digest: line when the plan has destructive rows, and Approval token: <token>.
The Plan computed for <app> — no infrastructure was modified. note, the consent instruction and the Apply with: line are conversation on stderr. So fjall deploy api --plan > plan.txt captures the plan, the ticket and the token, and nothing else.
fjall domain deploy example.com --plan splits its output the same way.
Deploy the organisation for the first time
Understanding output
Where the output goes
On the non-interactive path (a pipe, a redirect,--non-interactive, or CI) a deploy splits its output across two streams.
The URL is the deploy’s result, so a shell captures it with nothing to strip.
Next Steps: block names the URL again on stderr, under Visit your site: or Visit your url:, or as Setup your account: with /admin appended, depending on the application pattern.
A deploy writes nothing to stdout when the application has neither a load balancer nor a CloudFront distribution, such as a Lambda-only or queue-worker application. A failed deploy writes nothing to stdout either, so branch on the exit code rather than on whether stdout was empty.
--plan is the exception. The plan is that run’s result, so the plan rows and the Approval token: line are what lands on stdout. See Plan first, then approve.
At a TTY the interactive screen draws on stdout as usual. The split above describes the non-interactive lane.
Progress indicators
Handling failures
If a deploy fails:
- Read the error for the specific failure message.
- Check the stack in the CloudFormation console for resource-level detail.
- Let CloudFormation roll back, which it does automatically on failure.
- Fix the cause and rerun.
Exit codes
Best practices
- Read the plan card before approving. It names every replace and every data-loss row.
- Deploy to a non-production target first.
- Run
--planin CI and gate the apply on the returned token. - Back up data before a change that replaces a database.
Next Steps
Destructive changes
Understand the consent ceremony and exit code 4.
Understanding profiles
See how authentication and account selection are derived.
Detect drift
Find and repair resources changed outside CloudFormation.
Roll back a release
List recorded releases and roll back to a known-good one.
A first deployment typically takes 10 to 15 minutes. Later deploys are faster,
because only changed resources are modified.