# Deploying

`flatstack deploy` builds your project into one bundle and uploads it. Until the CLI ships, the same steps are available as an API.

## What a deploy does

1. Your functions (`flatstack/functions/*.ts`) and routes (`flatstack/routes/*.ts`) are bundled with the Flatstack runtime into a single module. Two functions with the same name, or a bundle over 10 MB compressed, stop the build.
2. The deploy is [scanned for security problems](security-scan.md). A critical finding stops it here, before anything changes, unless you force it with the project's slug.
3. Pending [migrations](migrations.md) are applied to the environment's database. If one fails, the database is left unchanged and the deploy stops.
4. The bundle goes live with your environment's database, variables and secrets, and its [cron jobs](cron.md) replace the environment's. Secrets are decrypted only to be handed to your app; they never appear in deploy records or logs.
5. The new version replaces the old one in one step. If it fails to start, for example because a route is under the reserved `/api/data` or `/api/stripe`, the deploy fails and the previous version keeps serving.

## API

| Request | Who | What it does |
| --- | --- | --- |
| `POST /v1/projects/{id}/deploys` | Owners, admins, developers, deploy tokens | `{ "script", "environment"?, "commitSha"?, "migrations"?, "allowDestructive"?, "sources"?, "assets"?, "dependencies"?, "forceInsecure"?, "cron"? }`. `environment` defaults to `production`. `sources` and `assets` are `[{ "path", "content" }]`, `dependencies` is `[{ "name", "version" }]`; the [security scan](security-scan.md) reads them. `cron` is what `flatstack/cron.ts` passes to `cron()`, such as `{ "0 * * * *": "cleanup" }` ([Cron jobs](cron.md)). Returns the deploy with `status: "succeeded"`, its `scan`, `cron` jobs and `warnings`. |
| `GET /v1/projects/{id}/deploys` | Everyone | The project's last 50 deploys, newest first. |
| `GET /v1/projects/{id}/deploys/{deployId}` | Everyone | One deploy's status. |
| `POST /v1/projects/{id}/deploys/{deployId}/rollback` | Owners, admins, developers, deploy tokens | Puts an earlier deploy back live, as a new deploy. |

A failed deploy returns `422 deploy_failed` with `details.deployId` and `details.reason`. A deploy with a critical scan finding returns `422 deploy_blocked_by_scanner` with `details.deployId` and `details.scan`, and is listed with `status: "blocked"`. A bundle over 10 MB compressed returns `413 bundle_too_large`. A cron schedule that doesn't parse returns `400 validation_failed` with `details.cron`, and one that runs more often than your plan allows returns `422 cron_interval_too_short`; neither records a deploy.

## Rolling back

You can roll back to any of your environment's last 20 deploys that went live. Rollbacks aren't scanned again; they keep the findings of the deploy they put back. `canRollBack` on each deploy says whether it's still available. Rolling back changes the code and its cron jobs: the environment's current variables and secrets are used.

A deploy token can deploy and roll back only its own project, and only its environment if it was created for one.