# Deploy an app

> Deploy a branch, tag or commit of a git app or a new image reference, redeploy to apply changed settings, and cancel a deployment.

Source: https://docs.coritan.com/apps/deploy-an-app/

In the dashboard:

- /dashboard/apps/…/deployments: https://www.coritan.com/dashboard/apps

A deployment runs one version of an app. Deploy to ship a new version: a branch, a tag or a commit of a git app, or an image reference for an image app. Redeploy to run the current version again, which applies settings that only a new deployment picks up. Each deployment goes live only once its replicas are healthy, and the current one serves until then ([Deployments](/apps/how-apps-work/#deployments)). In the dashboard, **Deploy…** and **Redeploy…** are in the app's header, and the **Deployments** tab lists every deployment.

## Before you begin

- Open the app from **Apps** in the [dashboard](https://www.coritan.com/dashboard/apps).
- The app must be `active`. While it is suspended, **Deploy…** and **Redeploy…** are turned off, and the API refuses to deploy it.
- For an organization's app, you need the owner or admin role in the organization.
- A push webhook can deploy each push to the app's branch for you ([Deploy on every push](/apps/push-webhook/)).

## Deploy in the dashboard

1. Open the app and select **Deploy…**.
2. In **Branch, tag or commit**, type what to deploy ([Choose what to deploy](#choose-what-to-deploy)). It holds the app's branch at first, such as `main`. For an image app, the field is **Image reference** and holds the app's saved image.
3. Select **Deploy**.

A message confirms `Deployment started.`, and the new deployment's page opens ([Read a deployment and its build log](/apps/read-a-deployment/)). When the field is refused, the message under it says why. Any other refusal appears in the dialog under `Could not start the deployment`.

## Choose what to deploy

A git app builds the version you name:

The app's branch
: The default. The build takes the newest commit on the branch when it starts.

Another branch
: Its name, such as `release`. The app keeps its own branch for pushes and redeploys.

A tag
: The full name of the tag, such as `refs/tags/v1.4.0`. A bare tag name, such as `v1.4.0`, is looked for as a branch and the build fails.

A commit
: Through the API only, as `git_sha`: its full ID, 40 characters (64 in a repository that uses SHA-256), with or without a branch. A shorter ID is ignored, and the build takes the newest commit on the branch instead. The dashboard's **Branch, tag or commit** field looks for a commit ID as a branch, so the build fails. We fetch the commit by its ID. If the host does not serve commits that way, we fetch the branch, and the build fails when the branch has moved past that commit.

An image app runs its saved image unless you name another reference, such as `ghcr.io/example/web:1.5.0`. The reference you name runs for this deployment only, and the app keeps its saved image. To change the image the app keeps, change it on the **Settings** tab ([Change or delete an app](/apps/app-settings/)).

## Redeploy

A redeploy runs the image of the deployment that serves the app again, with the app's settings as they are now. It applies changes to the variables the running app reads, the size, the regions and the number of replicas.

A redeploy with a rebuild builds the app's branch again, which applies changes to the repository, the branch, the directory, the access token, the build settings and the variables the build reads. For an image app, it deploys the image the app keeps, so after you change an image app's image, redeploy with a rebuild: a plain redeploy runs the image that is running now. An app that has nothing deployed yet always builds or pulls afresh.

To redeploy in the dashboard:

1. Select **Redeploy…** in the app's header. It is there once a deployment serves the app.
2. To rebuild, tick **Build the branch again**. For an image app, the box is **Pull the image again**.
3. Select **Redeploy**.

A message confirms `Redeploy started.`, and the new deployment's page opens.

After you save a change that only a new deployment applies, a note under the app's header says so: `A redeploy applies the saved changes`, `A new build applies the saved changes`, or for an image app `The new image is not running yet`. Its **Redeploy…** button opens the same dialog, with the box ticked when the change needs a rebuild. Through the API, the answer to the change says which one it needs ([Change settings through the API](/apps/app-settings/#change-settings-through-the-api)).

## Cancel a deployment

You can cancel a deployment that is still `queued`, `building` or `deploying`. Its build stops, its replicas are removed, and its status becomes `canceled`. The deployment that serves the app goes on serving. A deployment that has finished cannot be cancelled.

1. On the **Deployments** tab, open the menu at the end of the deployment's row and select **Cancel deployment…**. On the deployment's own page, **Cancel deployment…** is in its header.
2. Select **Cancel deployment** to confirm, or **Keep it** to leave it running.

A message confirms `Deployment cancelled.`, and the deployment shows **Cancelled**.

## Read the deployment history

The **Deployments** tab lists the app's deployments, newest first, 20 to a page. Its card says how many there are, such as `14 deployments, newest first.`

**Deployment**
: The first line of the commit message, or what the deployment was, such as `Redeploy`, `Rollback` or `Build of main`. **Current** marks the one that serves the app. Under it are the short commit and the branch or tag, or the image. A failed deployment also shows why it failed.

**Status**
: **Queued**, **Building**, **Deploying**, **Ready**, **Failed**, **Cancelled** or **Superseded** ([Status words](/apps/fields/#status-words)). While a deployment is on its way, the line under it says what it is doing, such as `Starting replicas` or `Waiting for a builder`. The current deployment's line says how many of its replicas are healthy.

**Source**
: What started it, such as `Push to main`, `Deploy of main` or `Rollback`, and who, such as `You` or `The push webhook`.

**Created**
: When it was created, and how long it took, such as `Took 3 min 12 s`, or `45 s so far` while it is on its way.

Select a row to open the deployment's page. The menu at the end of each row has **Open deployment**, **Roll back to this…** for a version you can go back to ([Roll back to an earlier deployment](/apps/roll-back-a-deployment/)), **Cancel deployment…** for one on its way, and **Copy deployment ID**. While a deployment is on its way, the first page updates on its own.

## Result

The new deployment is first on the **Deployments** tab. It moves to **Ready** and serves the app once its replicas are healthy in every region, or it ends as **Failed** or **Cancelled** and the current deployment keeps serving. [Read a deployment and its build log](/apps/read-a-deployment/) shows how to follow it.

## Troubleshooting

`The app is suspended; it cannot deploy`
: We suspended the app. [Contact support](/support/conversations/) to find out why.

`This app builds from git. Deploy a branch or a commit instead`
: An image reference was sent for a git app. For an image app, the message says it runs an image.

`git could not fetch v1.4.0 from https://github.com/example/web-shop.`
: The branch does not exist. For a tag, give its full name, such as `refs/tags/v1.4.0`. For a commit, deploy it through the API with `git_sha`. For a private repository, check that the access token can still read it.

`release has moved past commit 9f2c1e7b4a6d, and github.com does not serve an older commit by its id. Deploy the branch again.`
: The host would not send the commit by its ID, and the branch no longer ends at it. Deploy the branch, or push a branch that ends at that commit.

`The deployment is ready; only a deployment on its way can be canceled`
: The deployment has finished. To stop serving it, deploy another version or roll back ([Roll back to an earlier deployment](/apps/roll-back-a-deployment/)).

`Too many deployments of this app. Wait a few minutes.`
: The app started 30 deployments in the last 10 minutes. Wait, then deploy again.

## Related

- [Read a deployment and its build log](/apps/read-a-deployment/)
- [Roll back to an earlier deployment](/apps/roll-back-a-deployment/)
- [Deploy on every push](/apps/push-webhook/)
- [How Apps works](/apps/how-apps-work/)

## With the API

Each request takes the app's `uuid`. For an organization's app, send the same request under `/api/v1/orgs/{org_slug}/apps` ([organization apps reference](/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps-app-uuid-deployments)).

### Deploy through the API

[`POST /api/v1/client/apps/{app_uuid}/deployments`](/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-deployments) starts a deployment. An empty body deploys the app's branch or its saved image.

`git_ref`
: For a git app. A branch name, or a full ref such as `refs/tags/v1.4.0`. The app's branch when left out.

`git_sha`
: For a git app. A commit's full ID.

`image_ref`
: For an image app. The image to run this time. The app's saved image when left out.

```bash
curl -X POST https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/deployments \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"git_ref": "refs/tags/v1.4.0"}'
```

It answers `201` with the new deployment:

```json
{
  "deployment": {
    "uuid": "0b6f3d2e-7a41-4c59-8e1d-2f9a6b3c4d5e",
    "status": "queued",
    "source": "git",
    "trigger": "manual",
    "git_ref": "refs/tags/v1.4.0",
    "git_sha": null,
    "image_ref": null,
    "regions": null,
    "error": null,
    "is_current": false,
    "in_flight": true,
    "can_rollback": false,
    "replicas": {"healthy": 0, "unhealthy": 0, "starting": 0, "total": 0},
    "build": {"uuid": "e2a9c4d1-3b5f-4e7a-9c8d-1f2e3a4b5c6d", "status": "queued", "strategy": null, "attempts": 0},
    "created_at": "2026-09-26T10:05:00Z"
  }
}
```

The example leaves some fields out. [App and deployment fields](/apps/fields/#deployment) describes each one. `regions` stays `null` until the deployment starts placing replicas.

| Status | `detail` | Cause |
| --- | --- | --- |
| `409` | `{"error": "source_mismatch", "message": "This app runs an image. Deploy an image reference instead"}` | A branch or commit was sent for an image app, or an image for a git app. |
| `409` | `{"error": "app_not_active", "message": "The app is suspended; it cannot deploy"}` | The app is suspended. |
| `422` | `Give a branch or commit, or an image reference, not both` | The body held both. |
| `422` | `{"error": "repository_invalid", "message": "'release..x' is not a branch name git accepts."}` | `git_ref`, or the app's repository settings, cannot be fetched. |
| `503` | `{"error": "registry_not_configured", "message": "Builds are not available on this platform yet."}` | The platform cannot build images at the moment. An image app can still deploy. |
| `429` | `{"error": "rate_limited", "message": "Too many deployments of this app. Wait a few minutes.", "retry_after_seconds": 600}` | The app started 30 deployments in the last 10 minutes. |

### Redeploy through the API

[`POST /api/v1/client/apps/{app_uuid}/redeploy`](/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-redeploy) runs the current version again. Send `{"rebuild": true}` to build the branch again, or for an image app to deploy its saved image. The body can be left out.

```bash
curl -X POST https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/redeploy \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"rebuild": false}'
```

It answers `201` with the new deployment, as above. A redeploy that reuses the image has `source` `redeploy` and starts as `deploying`. It refuses a suspended app and counts towards the same limit of 30 deployments in 10 minutes.

### Cancel through the API

[`POST /api/v1/client/apps/{app_uuid}/deployments/{deployment_uuid}/cancel`](/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-deployments-deployment-uuid-cancel) cancels a deployment on its way, and answers with it, now `canceled`, and its replicas:

```bash
curl -X POST https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/deployments/0b6f3d2e-7a41-4c59-8e1d-2f9a6b3c4d5e/cancel \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

A deployment that has finished answers `409` with `The deployment is ready; only a deployment on its way can be canceled`, naming its status. One that belongs to another app answers `404` with `Deployment not found`.

### List deployments

[`GET /api/v1/client/apps/{app_uuid}/deployments`](/api/reference/client/apps/#op-get-api-v1-client-apps-app-uuid-deployments) lists the app's deployments, newest first:

```bash
curl "https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/deployments?limit=20&offset=0" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "deployments": [
    {"uuid": "0b6f3d2e-7a41-4c59-8e1d-2f9a6b3c4d5e", "status": "ready", "source": "git", "trigger": "manual", "is_current": true},
    {"uuid": "8c4e1a7d-2f9b-4d6e-b3a8-6e1f9c2d5a10", "status": "superseded", "source": "git", "trigger": "push", "is_current": false}
  ],
  "total": 14,
  "limit": 20,
  "offset": 0
}
```

`limit` takes 1–100 (20 when left out), `offset` skips that many deployments, and `total` counts them all. Each deployment carries every field, shortened here.

## API

- `GET /api/v1/client/apps/{app_uuid}/deployments`: List an app's deployments, newest first, a page at a time (https://docs.coritan.com/api/reference/client/apps/#op-get-api-v1-client-apps-app-uuid-deployments)
- `POST /api/v1/client/apps/{app_uuid}/deployments`: Create app deployment (https://docs.coritan.com/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-deployments)
- `POST /api/v1/client/apps/{app_uuid}/deployments/{deployment_uuid}/cancel`: Cancel a deployment that is still queued, building or deploying (https://docs.coritan.com/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-deployments-deployment-uuid-cancel)
- `POST /api/v1/client/apps/{app_uuid}/redeploy`: Redeploy app (https://docs.coritan.com/api/reference/client/apps/#op-post-api-v1-client-apps-app-uuid-redeploy)
- `GET /api/v1/orgs/{org_slug}/apps/{app_uuid}/deployments`: List an app's deployments, newest first, a page at a time (https://docs.coritan.com/api/reference/organizations/organization-apps/#op-get-api-v1-orgs-org-slug-apps-app-uuid-deployments)
- `POST /api/v1/orgs/{org_slug}/apps/{app_uuid}/deployments`: Create app deployment (https://docs.coritan.com/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps-app-uuid-deployments)
- `POST /api/v1/orgs/{org_slug}/apps/{app_uuid}/deployments/{deployment_uuid}/cancel`: Cancel a deployment that is still queued, building or deploying (https://docs.coritan.com/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps-app-uuid-deployments-deployment-uuid-cancel)
- `POST /api/v1/orgs/{org_slug}/apps/{app_uuid}/redeploy`: Redeploy app (https://docs.coritan.com/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps-app-uuid-redeploy)
