> ## Documentation Index
> Fetch the complete documentation index at: https://docs.judt.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Commits and deployments

> Understanding lifecycle and code history

In Judt, editing files in the sandbox never changes your live production App directly. To publish changes to production, you save a **commit** and then create a **deployment** from that commit.

## Commits

A commit is an immutable snapshot of your App's `/app` directory stored in Git and backed up inside of Judt. You can restore a commit later if needed.

### Create a commit

After you edit files or run commands in the sandbox, call `POST /api/apps/{id}/commits`:

```bash theme={null}
curl -X POST https://api.judt.ai/api/apps/$APP_ID/commits \
  -H "Authorization: Bearer $JUDT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "Add /health endpoint"}'
```

The API stages all tracked and untracked files in `/app` (respecting `.gitignore`), creates a Git commit, saves a durable backup, and returns a `Commit` object:

```json theme={null}
{
  "id": "cmt_3xK9mQ2pRtV7nW4sLc8ZbY5j",
  "app_id": "app_8fK2mQ7xRtV3nW9pLc4ZbY1s",
  "commit_sha": "7b3c9e1d4a2f8056e1c9d0b4f2a6e8c1d3b5a7f9",
  "message": "Add /health endpoint",
  "created_by": "USER_ID",
  "created_at": "2026-10-15T20:20:00.000Z"
}
```

| Identifier | Where to use it |
| - | - |
| `id` (`cmt_...`) | Pass as `commit_id` to `POST /api/apps/{id}/restore` to reset the sandbox working tree to this snapshot, or to `POST /api/apps/{id}/deployments` to deploy this commit to production. |
| `commit_sha` (40-char hex) | Pass as the `commit_sha` filter to `GET /api/apps/{id}/commits` or `GET /api/apps/{id}/deployments` to find a commit or its deployments. |

To list existing commits without starting the sandbox, call `GET /api/apps/{id}/commits`.

## Deployments

A deployment builds a commit in a clean container, runs any D1 database migrations, injects your App's Secrets, and publishes the bundle to production.

### Create a deployment

Call `POST /api/apps/{id}/deployments`:

```bash theme={null}
curl -X POST https://api.judt.ai/api/apps/$APP_ID/deployments \
  -H "Authorization: Bearer $JUDT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

* **Deploy the sandbox**: Send `{}` to deploy the sandbox's files. If they changed since the last commit, Judt commits them first and then deploys that commit.
* **Deploy a specific commit**: Send `{"commit_id": "cmt_..."}` to deploy that exact commit (for example, to roll back to an earlier version).

> [!NOTE]
>
> To write your own commit message, call `POST /api/apps/{id}/commits` before you deploy.

Only one deployment can run at a time for an App. If another deployment is still running, the API returns `409 deployment_unsettled`.

### What happens during a deployment

When you create a deployment, Judt executes these steps in order:

1. **Export the commit**: Reads the commit snapshot from Git and verifies source limits (up to `2,048` files and folders, `32 MiB` total uncompressed size, and `1 MiB` per file).
2. **Validate `wrangler.json`**: Checks the App configuration and storage bindings. See [The App contract](https://docs.judt.ai/build/app-contract.md) and [Configure wrangler.json](https://docs.judt.ai/build/wrangler-json.md).
3. **Run `before` migrations**: If the App has existing D1 databases with pending schema migrations, applies them before the new code goes live.
4. **Install dependencies and build**: If `package.json` declares dependencies, requires a `package-lock.json` file (`422 lockfile_missing`) and runs `npm ci --ignore-scripts`. Then runs `npm run build` (when a `build` script is defined) inside an isolated build container. Secrets are not exposed during the build step. See [npm packages and builds](https://docs.judt.ai/build/npm-and-builds.md).
5. **Inject Secrets and publish**: Injects the App's current Secrets into the deployed `vars` configuration and publishes the bundle to the production runtime.
6. **Verify activation**: Probes the production runtime to confirm the new deployment starts cleanly.
7. **Run `after` migrations**: Applies initial D1 migrations for any newly created D1 databases.

### The Deployment object

`POST /api/apps/{id}/deployments` waits for the pipeline to finish (up to 540 seconds) and returns the `Deployment` object:

```json theme={null}
{
  "id": "dep_4hN8vX2kPq6TmR1wLs9CdF3j",
  "app_id": "app_8fK2mQ7xRtV3nW9pLc4ZbY1s",
  "commit_id": "cmt_3xK9mQ2pRtV7nW4sLc8ZbY5j",
  "commit_sha": "7b3c9e1d4a2f8056e1c9d0b4f2a6e8c1d3b5a7f9",
  "status": "succeeded",
  "error": null,
  "migrations": {
    "databases": [],
    "before": null,
    "after": null,
    "detail": null
  },
  "published_at": "2026-10-15T20:21:07.000Z",
  "created_at": "2026-10-15T20:21:00.000Z"
}
```

### Deployment status

The `status` field says where the deployment is:

| Status | Meaning |
| - | - |
| `publishing` | The version is being built and published, after any database migrations that must run first. |
| `starting` | Production points to this version, and it is starting. |
| `succeeded` | The version started serving. |
| `failed` | The version was not published, or it did not start serving. `error` says why. |
| `disabled` | The App was deleted while the version was publishing, so the version never served. |

> [!NOTE]
>
> A deployment stays `succeeded` after a newer deployment replaces it or the App is unpublished. To check which deployment is serving right now, inspect `production.deployment_id` on `GET /api/apps/{id}`.

If a deployment fails during build, migration, publication, or activation, `error.code` and `error.message` explain why, and the previous production deployment continues serving if the failure happened before publication.

## Unpublish an App

To take an App offline without deleting it, call `POST /api/apps/{id}/unpublish`:

```bash theme={null}
curl -X POST https://api.judt.ai/api/apps/$APP_ID/unpublish \
  -H "Authorization: Bearer $JUDT_API_KEY"
```

Unpublishing stops the production runtime and sets `production.status` to `"unpublished"` and `production.deployment_id` to `null`. The App's source code, commits, Secrets, and runtime storage remain intact. Call `POST /api/apps/{id}/deployments` at any time to publish the App again.

## Next steps

* Follow step-by-step procedures to publish, roll back, and unpublish in [Publish and unpublish an App](https://docs.judt.ai/manage/guides/publish.md).
* Learn how D1 migrations and storage bindings behave across deployments in [The App contract](https://docs.judt.ai/build/app-contract.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.