Deploying with Kamal
Kamal deploys; Upstate verifies. Upstate does not build, push, migrate, roll back, or SSH into your application on your behalf. It receives a deploy's intent and outcome through hooks, then compares that with fresh independent observer reports and configured health checks.
Choose the right command
| Situation | Command | What Upstate gets |
|---|---|---|
| Normal connected project with managed hooks | kamal deploy or bin/kamal deploy | Hooks create the lifecycle receipt. |
| You prefer the Upstate Kamal launcher | upstate kamal deploy | The same Kamal deployment and lifecycle receipt (hooks if installed, otherwise wrapper fallback); no extra command-activity or facts record. |
| Connected but hooks unavailable | upstate kamal deploy --version VERSION | Wrapper can report the lifecycle using an explicit version. |
| A specific image is already built and pushed | upstate kamal deploy --skip-push --version VERSION | Kamal reuses the named image; review your own build/push and migration workflow first. |
| A prior release needs to be restored | upstate kamal rollback VERSION | Kamal performs the rollback; Upstate reports and verifies its outcome. |
Commands and options after upstate kamal go directly to the project's Kamal binary. An Upstate failure does not change Kamal's exit code. You can keep running the ordinary Kamal commands you already use; adding the wrapper is not a prerequisite for receipts when managed hooks are installed. The wrapper's bounded activity reporting and optional parsed facts apply to non-deploy commands, with fact capture limited to upstate kamal app details, proxy details and accessory details. See CLI command reference for metadata and privacy details.
One-time setup
From the existing application's repository:
upstate connect --dry-run
upstate connect
upstate doctor
upstate observer statusCheck the discovered service, destination, roles and servers. Confirm the correct account and ensure the observer is actually reporting. A configured observer without a fresh report is insufficient for independent verification.
Connect installs composed pre/post-deploy hooks and preserves any existing hooks. It does not overwrite custom deployment behavior silently. Dynamic/ERB Kamal configuration may require explicit service, target and host mapping. See Getting started and The host observer.
Recommended deployment flow
# Read current production evidence
upstate status
# Deploy your application with its usual destination/version options
upstate kamal deploy
# This is an Upstate verification step, not another deployment
upstate receipt --watch
# Inspect details or open the evidence page
upstate receipt
upstate open --receiptFor a script, use upstate receipt --json to read the resulting receipt only when the checkout's saved app/environment mapping matches the deployment. Its final state is more meaningful than assuming that Kamal's exit code alone proves observed production health. For another service or destination, select its receipt explicitly as shown below.
When the release requires database changes, decide separately when migrations should run and which application image owns them. Upstate does not infer schema compatibility or run migrations. Preserve compatibility between web and worker roles during rolling deployments.
When you have a prebuilt image
Kamal itself supplies image build, push, pull, deploy, details and migration commands. Keep an explicit immutable version throughout your existing release procedure. For example, if your process has already built and published a versioned image:
upstate kamal deploy --skip-push --version release-2026-11-03
upstate kamal app details --version release-2026-11-03
upstate receipt --watchOnly use --skip-push after confirming the target hosts can pull that specific image. The example is not a substitute for your application's image-publishing or migration steps. If your repository supplies bin/kamal, the wrapper invokes it instead of bypassing it.
What happens during a deployment
- A pre-deploy hook records the intended app, destination, version and target roles/hosts. With managed hooks, Kamal supplies the exact version.
- Kamal does its normal work, including application lifecycle and your existing hooks.
- A post-deploy hook records completion. The observer reports actual running containers independently, normally each minute.
- Upstate evaluates intended instance coverage, version convergence and required HTTP or app checks, then records a durable verdict.
The receipt can be Verifying, Verified, Needs attention, Incomplete or Superseded. An uninstrumented project may have a legacy receipt that cannot be fully verified. Read Deployment receipts to interpret evidence and grace periods.
Your app can be healthy before the post-deploy hook arrives; Upstate preserves observation timestamps rather than inventing ordering. A missed hook is not the same as a failed container; missing observer reports are not proof the application is down.
Multiple destinations and services
Use the destination and config you would pass to Kamal normally:
upstate kamal deploy -d production
upstate kamal deploy -c config/deploy.edge.yml
upstate connect --config config/deploy.edge.yml --dry-runEach service/destination needs a correct mapping. Connect does not evaluate ERB, and a single repository can contain more than one Kamal service. Confirm the mapping before letting a wrapper report the deployment to an account.
Verification commands do not inherit Kamal's -d or -c options. Bare upstate receipt --watch, upstate receipt --json and upstate logs use the checkout's saved .upstate app/environment mapping and may select an older deployment for the default environment. If you deploy to another destination or service, find that deployment's receipt ID (dep_...) in Upstate's deployment history or its receipt link, then target it directly:
upstate receipt --id dep_example --watch
upstate receipt --id dep_example --json
upstate logs dep_example --lines 100 --since 15mThe explicit receipt ID is the link between the deployed version, its verification evidence, and the role/host-scoped logs. A Verified receipt from a different environment is not verification of the deployment you just ran.
Diagnose or recover
# Latest receipt and logs for this checkout's saved mapping
upstate receipt --json
upstate logs --lines 100 --since 15m
# Or target a known receipt from any mapped destination/service in the account
upstate receipt --id dep_example --json
upstate logs dep_example --lines 100 --since 15m
upstate kamal app details
upstate kamal proxy details
upstate hook flushA receipt may suggest follow-up commands with IDs such as dep_example.1. Inspect them in the JSON output and use upstate run dep_example.1 to see the command and confirm it. Upstate does not silently run those suggestions, perform remediation or roll back a release.
upstate hook flush retries safely retained lifecycle reports, not the Kamal deployment. Missing post-deploy evidence may result in an Incomplete receipt. If the observer is stale, investigate its service or network access before treating old runtime data as current.
Current limitations
Preflight checks and the --wait/--strict deploy flags need CLI v0.2.11 or later. Check upstate version; with an older CLI, use upstate receipt --watch as a separate step. The observer is read-only; neither a receipt nor a passing HTTP check proves backups can be restored, background work is complete or all user flows succeed.