---
name: runlot-deploy
description: Deploy and ship apps on Runlot with the runlot CLI — first deploy, `runlot deploy`, preview deployments with their own database branch, versions and rollback, custom domains, access control, secrets, deploying from CI with RUNLOT_TOKEN, push-to-deploy, and reading deploy errors such as a compatibilityDate refusal or bundle_too_large. Use when deploying, releasing, rolling back, previewing a branch, connecting a domain, or a Runlot deploy fails.
---

# Deploy on Runlot

`runlot deploy` bundles the worker **on your machine** with esbuild, uploads the result, and
switches the project to the new version. There is no remote build (except push-to-deploy), so
a build error shows up before anything is uploaded.

## The loop

```bash
runlot dev            # run it locally on workerd first
runlot deploy         # bundle, upload, create the project if missing, apply migrations/
runlot health         # open capacity risks after the deploy
runlot logs           # live tail; Ctrl-C to stop
```

`runlot deploy [dir]` reads `name` and `org` from `runlot.json`; `--org` and `--project`
override them. A successful deploy prints the version line, then the addresses:

```text
Deploying…
v3  <deploymentId>  <artifact sha>  <createdAt>
  https://my-app.acme.runlot.app
```

What a deploy also does, in order: creates the project if it does not exist, creates the
database when the build uses one, applies `migrations/NNNN_*.sql` (skip with `runlot deploy --no-migrate`),
prints one line if capacity risks are open. Read every `Warning:` line it prints — each names
the exact edit.

## Before the first deploy

- `runlot whoami` must succeed (or `RUNLOT_TOKEN` is set).
- `runlot.json` has `name`, and `main` or `assets` (or `framework: "next"`).
- If the worker imports agent frameworks or late Node built-ins, set `compatibilityDate`
  (see [references/deploy-errors.md](references/deploy-errors.md)).
- Secrets the code reads exist: `runlot secret list`.

## Choose the right command

| Goal | Command |
|---|---|
| Try a change at a second address with a copy of the data | `runlot deploy --preview <name>` |
| Ship a preview's exact code to production | `runlot preview promote <name>` |
| Undo a bad release | `runlot versions`, then `runlot rollback <version>` |
| Put the app on your own domain | `runlot domain add <host>` |
| Limit who can open the deployment | `runlot access set org` (or `password`, `app`, `public`) |
| Deploy from CI | `RUNLOT_TOKEN=<token> runlot deploy` |
| Open the live address | `runlot open` |

Details: [references/previews-and-rollback.md](references/previews-and-rollback.md),
[references/domains-and-access.md](references/domains-and-access.md),
[references/ci.md](references/ci.md), [references/frameworks.md](references/frameworks.md).

## When a deploy fails

Read the error code in `Error [code] message`. The common ones and their fixes are in
[references/deploy-errors.md](references/deploy-errors.md). For an error that looks like
Runlot's fault (5xx, a deploy that hangs, an error that contradicts the docs), the CLI prints
a hint; follow it with `runlot bug-report --last` (see the `runlot-operate` skill).

## Do

- Deploy previews for risky changes and load tests; they get their own database branch.
- Keep migrations forward-only and deploy them before the code that needs them, or together.
- Check `runlot versions` before a rollback so you name the right version.
- Use a scoped token in CI (`--scope deploy --scope project:read`), not a personal login.

## Don't

- Don't use `--db shared` on a preview unless you mean to write to production's database.
- Don't expect `runlot rollback` to roll back the database; it changes only the code.
- Don't commit `.env.runlot` or `.runlot/`; don't put `node_modules` or build caches in `assets`.
- Don't rename a project casually: `runlot project rename` changes its address with no alias.
