> ## 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.

# Publish and unpublish an App

> Publish a commit to production, go back to an earlier commit, and take an App offline.

This guide shows how to publish changes from an App's sandbox to production, how to roll back production to an earlier commit, and how to take a published App offline.

> [!NOTE]
>
> Publishing and unpublishing an App requires the `owner` or `admin` role in the organization.

## Publish new changes to production

A deployment always publishes a commit. If the sandbox files changed since the last commit, the deployment commits them first.

**1. Verify your changes on the sandbox dev server**

Before you commit, start a preview to verify that the App bundles and runs cleanly:

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

If the build fails, the API returns `422 preview_failed` with the compiler error in `error.detail`.

**2. Check what changed**

Inspect the modified and untracked files in `/app`:

```bash theme={null}
curl "https://api.judt.ai/api/apps/$APP_ID/git?mode=status" \
  -H "Authorization: Bearer $JUDT_API_KEY"
```

**3. Create a commit**

Commit the sandbox changes to Git and create a durable backup:

```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 /api/orders endpoint"}'
```

This step lets you write your own commit message. If you skip it, the deployment commits any changes for you.

**4. Deploy the commit**

Publish the sandbox to production:

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

The request builds the App, applies any D1 migrations, publishes the bundle, and waits until the production runtime is serving:

```json theme={null}
{
  "id": "dep_4hN8vX2kPq6TmR1wLs9CdF3j",
  "commit_id": "cmt_3xK9mQ2pRtV7nW4sLc8ZbY5j",
  "commit_sha": "7b3c9e1d4a2f8056e1c9d0b4f2a6e8c1d3b5a7f9",
  "status": "succeeded",
  ...
}
```

## Roll back to an earlier commit

Every commit in your App's history has a 40-character `commit_sha` and a `cmt_...` ID. You can redeploy any earlier commit directly to production.

**1. Find the commit to restore**

List the App's commits:

```bash theme={null}
curl "https://api.judt.ai/api/apps/$APP_ID/commits?limit=10" \
  -H "Authorization: Bearer $JUDT_API_KEY"
```

Find the target commit in `results` and copy its `id` (`cmt_...`).

**2. Deploy the earlier commit to production**

Pass the commit's `cmt_...` ID in the `commit_id` field of `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 '{
    "commit_id": "cmt_1xK4mQ9pRtV2nW8sLc5ZbY3j"
  }'
```

When the request returns with `status: "succeeded"`, production is serving that earlier commit.

**3. Optional: Reset the sandbox working tree**

Deploying an earlier commit changes production, but leaves the sandbox `/app` directory on its current commit. If you also want to reset `/app` in the sandbox to match that commit, call `POST /api/apps/{id}/restore` with the commit's `cmt_...` ID:

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

> [!WARNING]
>
> Rolling back code does not reverse D1 database schema migrations that have already been applied. Write backward-compatible D1 migrations so earlier commits can still read the database if you roll back. See [D1](https://docs.judt.ai/build/storage/d1.md).

## Take an App offline (unpublish)

To stop serving an App in production without deleting the App, 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"
```

The API returns the updated App object with:

* `production.status`: `"unpublished"`
* `production.deployment_id`: `null`

Requests to the App's URL no longer reach your Worker. Your source files, commits, Secrets, and D1 / KV / R2 / Durable Object data remain untouched. Call `POST /api/apps/{id}/deployments` whenever you are ready to put the App back online.

## Next steps

* Understand the full build and migration pipeline in [Commits and deployments](https://docs.judt.ai/manage/concepts/deployments.md).
* Diagnose failed builds or unhealthy deployments in [Troubleshoot an App](https://docs.judt.ai/manage/guides/troubleshoot.md).


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