# Create an app

> Create an app from a git repository or a container image, choose its size, regions and replicas, and start its first deployment.

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

In the dashboard:

- /dashboard/apps/new: https://www.coritan.com/dashboard/apps/new

Create an app to run a web service from a git repository or from a container image. You create it on the dashboard's **New app** page, or through the API. Creating it also starts its first deployment unless you turn that off, so a working app is live once its replicas pass their health check.

## Before you begin

- Sign in to the [dashboard](https://www.coritan.com/dashboard/apps). **Apps** is in the sidebar only while Apps is on for the platform ([Limits and availability](/docs/apps/#limits-and-availability)).
- For a git app, the repository must be on a public host and reachable over HTTPS. For a private repository, create an access token on your git host that can read it.
- For an image app, the image must be one that anyone can pull, such as a public image on GitHub Container Registry or Docker Hub.
- Make sure the app listens on the port in its `PORT` variable and answers its health check path ([What your app must do](/docs/apps/how-apps-work/#what-your-app-must-do)).
- For an organization's app, you need the owner or admin role in the organization.
- You can have a set number of apps. The **Apps** list shows how many you have, such as `3 of 20 apps`, and [Regions, sizes and limits](/docs/apps/#regions-sizes-and-limits) shows how to read it through the API.

## Create an app in the dashboard

1. Go to **Apps** in the sidebar and select **New app…**.
2. Under **App**, type a **Name**, such as `Web shop`. The hint under it shows the address the app will answer at, such as `It answers at web-shop.apps.example.net, with a short suffix when that name is taken.`
3. Under **Source**, choose **Git repository** or **Ready image**.
   - For a git repository, fill in **Repository**, and change **Branch** when the app is not on `main`. Fill in **Directory** when the app is not at the top of the repository, and **Access token** when the repository is private.
   - For a ready image, fill in **Image**, such as `ghcr.io/example/web:1.4.0`.
4. Under **Regions**, choose **Every region**, or choose **The regions I choose** and tick each region you want. Then choose **Replicas per region**.
5. Under **Run**, check **Port**, **Health check path** and **Size**.
6. To change how a git app builds and starts, or to choose its name on the platform yourself, select **Show settings** on the last card. It is **Build and start** for a git app and **Name on the platform** for an image app.
7. Leave **Start the first deployment now** ticked to deploy as soon as the app exists, or untick it.

   > [!TIP]
   > The form has no environment variables. When the app needs some to build or start, untick **Start the first deployment now**, add them on the app's **Environment** tab, then deploy ([Set environment variables](/docs/apps/environment-variables/)).

8. Select **Create app**.

When a field is wrong, the message under it says why, and the form keeps what you typed. Any other refusal appears above the buttons under `Could not create the app`.

## What you choose

The **App** card:

**Name**
: What you call the app, up to 100 characters. You can change it later.

The **Source** card. Whether the app uses a **Git repository** or a **Ready image** cannot change later:

**Repository**
: For a git app, the repository's HTTPS address, such as `https://github.com/example/web-shop`, with no user name, token, query or fragment in it.

**Branch**
: The branch to build, `main` at first. Pushes to it deploy the app once you set up the push webhook.

**Directory**
: Where the app lives inside the repository. Leave it empty when the app is at the top.

**Access token**
: For a private repository. We keep it encrypted, use it only to fetch the code, and never show it again. The app shows its last four characters so you can tell which token it holds.

**Image**
: For an image app. A reference such as `ghcr.io/example/web:1.4.0`, or one pinned to a digest such as `ghcr.io/example/web@sha256:…`. It cannot be in the platform's own registry, which only holds images built from git.

The **Regions** card:

**Every region** or **The regions I choose**
: Every region that can run apps at the time of each deployment, which is the default, or up to 20 regions you tick. Each region shows its code and country.

**Replicas per region**
: How many replicas run in each region, from 1 to 5, 1 at first.

The **Run** card:

**Port**
: A number from 1 to 65535, `3000` at first, saved with the app. Each replica gets the port to listen on in its `PORT` variable, whatever this setting says.

**Health check path**
: The path we request to decide that a replica is healthy, `/` at first. It starts with `/`, such as `/healthz`.

**Size**
: The memory, CPU and disk each replica gets. Each option shows all three ([Replicas and regions](/docs/apps/how-apps-work/#replicas-and-regions)).

The **Build and start** card of a git app, under **Show settings**:

**Framework**
: A short lowercase label, such as `nextjs`, saved with the app. The build does not read it: Railpack works out the framework from the files.

**Dockerfile**
: A Dockerfile to build with, as a path inside the repository, such as `docker/Dockerfile`. Leave it empty to use a `Dockerfile` in the app's directory, or Railpack when there is none ([Builds](/docs/apps/how-apps-work/#builds)).

**Install command**, **Build command** and **Start command**
: Commands that replace the ones Railpack would choose, up to 500 characters each. A Dockerfile build does not use them.

On the same card, and on the **Name on the platform** card of an image app:

**Name on the platform**
: The app's unique name, such as `web-shop`, which its platform name `web-shop.<app domain>` is made from. It cannot change after you create the app ([Names on the platform](#names-on-the-platform)).

## Names on the platform

A name on the platform has 3 to 63 lowercase letters, digits and hyphens, and starts and ends with a letter or a digit. It cannot have hyphens in both its third and fourth places, and no other app on the platform can have it. Some words are reserved for the platform, such as `api`, `admin`, `app`, `status` and `www`.

When you leave it out, we make one from the app's name, such as `web-shop` for `Web shop`. When that one is taken or reserved, we add a hyphen and four random characters, as in `web-shop-k3x9`.

## What happens next

The dashboard confirms with a message such as `Web shop created.` and opens the first deployment's page, where the build log follows the build ([Read a deployment and its build log](/docs/apps/read-a-deployment/)). With no first deployment, it opens the app's **Deployments** tab.

A git app starts with a build of its branch, then starts replicas. An image app starts replicas at once.

A git app also gets a push webhook, and its secret is shown once. In the dashboard, the **Push webhook secret** dialog shows it with the **Payload URL**: copy both, or select **Copy all**, then select **I have saved it**. Through the API, the secret is in the answer to the request that creates the app. Save it if you want pushes to deploy the app ([Deploy on every push](/docs/apps/push-webhook/)). The **Settings** tab keeps the address and the secret's last four characters, and you can make a new secret there later.

If the first deployment cannot start, we still create the app and say why. The app's page shows `The first deployment did not start` with the reason and a **Deploy…** button. Fix the cause, then deploy it ([Deploy an app](/docs/apps/deploy-an-app/)).

## Result

The app is in the **Apps** list with its platform address, and its first deployment is on its way unless you turned it off. Once that deployment is **Ready**, the app is **Live** and answers at `https://<name on the platform>.<app domain>`.

## Troubleshooting

`The name web-shop is taken on the platform. Choose another`
: Another app has that name on the platform. Choose another, or leave it empty so that we make one.

`www is reserved. Choose another name`
: The name is one the platform keeps for itself. Choose another.

`Your account has as many apps as it may` or `The limit is 20 apps. Delete one before creating another`
: You have as many apps as you may, so **New app…** and **Create app** are turned off. Delete one you no longer need ([Change or delete an app](/docs/apps/app-settings/#delete-an-app)).

`The repository must be on a public host.` or `The repository URL must start with https://.`
: Give the repository's HTTPS address on a public host.

`Put the access token in the app's repository token, not in the URL.`
: Remove the user name or token from the address and put the token in **Access token**.

`The image must be on a public registry`
: The image's registry is on a private network. Push the image to a public registry.

`These regions cannot run apps: syd`
: The regions named cannot run apps now. Choose from the regions the platform offers, or choose every region.

`Too many apps created in the last hour. Wait a while and try again.`
: You created 20 apps in the last hour. Wait, then try again.

`Could not load the regions`
: The page could not read the regions and sizes it offers. Select **Try again**.

## Related

- [How Apps works](/docs/apps/how-apps-work/)
- [Deploy an app](/docs/apps/deploy-an-app/)
- [Set environment variables](/docs/apps/environment-variables/)
- [Add a custom domain](/docs/apps/custom-domains/)

## With the API

[`POST /api/v1/client/apps`](/docs/api/reference/client/apps/#op-post-api-v1-client-apps) creates an app of your own. For an organization's app, send the same body to [`POST /api/v1/orgs/{org_slug}/apps`](/docs/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps).

```bash
curl -X POST https://api.coritan.com/api/v1/client/apps \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Web shop",
    "source_type": "git",
    "repo_url": "https://github.com/example/web-shop",
    "repo_branch": "main",
    "repo_token": "github_pat_EXAMPLE",
    "health_check_path": "/healthz",
    "instance_size": "small",
    "regions": ["fra", "iad"],
    "min_replicas": 2,
    "env": [{"key": "DATABASE_URL", "value": "postgres://app:secret@db.example.com/shop"}]
  }'
```

The body takes these fields. Only `name` is required, and a git app also needs `repo_url`, an image app `image_ref`.

`name`
: 1–100 characters.

`slug`
: The name on the platform. Made from `name` when left out.

`source_type`
: `git`, the default, or `image`.

`repo_url`, `repo_branch`, `repo_subdir` and `repo_token`
: A git app's repository, branch (`main` when left out), directory and access token. An image app refuses them.

`image_ref`
: An image app's image reference. A git app refuses it.

`dockerfile_path`, `install_command`, `build_command`, `start_command` and `framework`
: How a git app builds and starts.

`port` and `health_check_path`
: `3000` and `/` when left out.

`instance_size`
: `small`, `medium` or `large`. `small` when left out.

`regions`
: `["*"]` for every region, the default, or a list of up to 20 region codes.

`min_replicas` and `max_replicas`
: Replicas in each region, 1–5 for `min_replicas` (1 when left out). `max_replicas` takes up to 10, and one below `min_replicas` is raised to it.

`env`
: A list of variables, each with `key`, `value` and optionally `secret` and `target` ([Set environment variables](/docs/apps/environment-variables/#with-the-api)).

`deploy`
: `true`, the default, starts the first deployment. `false` creates the app without one.

It answers `201`:

```json
{
  "app": {
    "uuid": "3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21",
    "name": "Web shop",
    "slug": "web-shop",
    "status": "active",
    "source_type": "git",
    "repo_token_set": true,
    "repo_token_hint": "MPLE",
    "url": "https://web-shop.apps.example.net"
  },
  "deployment": {
    "uuid": "0b6f3d2e-7a41-4c59-8e1d-2f9a6b3c4d5e",
    "status": "queued",
    "source": "git",
    "trigger": "manual",
    "git_ref": "main"
  },
  "deploy_error": null,
  "webhook": {
    "url": "https://api.coritan.com/api/v1/apps/hooks/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21",
    "secret": "4f1d2c3b5a69788796a5b4c3d2e1f0a94f1d2c3b5a69788796a5b4c3d2e1f0a9"
  }
}
```

The example shortens `app` and `deployment`, which carry every field ([App and deployment fields](/docs/apps/fields/)). `webhook.secret` appears in this answer only, and `webhook` is `null` for an image app. `deployment` is `null` when you sent `"deploy": false`, and also when the first deployment could not start, when `deploy_error` says why, as in `Builds are not available on this platform yet`.

| Status | `detail` | Cause |
| --- | --- | --- |
| `409` | `{"error": "slug_taken", "message": "The name web-shop is taken on the platform. Choose another"}` | Another app has the `slug` you sent. |
| `409` | `{"error": "app_limit", "message": "The limit is 20 apps. Delete one before creating another", "limit": 20}` | You have as many apps as you may. |
| `422` | `The app name on the platform must be 3 to 63 lowercase letters, digits and hyphens, starting and ending with a letter or digit` | The `slug` breaks the rules above. |
| `422` | `www is reserved. Choose another name` | The `slug` is reserved. |
| `422` | `{"message": "These regions cannot run apps: syd", "unavailable": ["syd"], "available": ["fra", "iad"]}` | A region in `regions` cannot run apps now. |
| `422` | `That is not an image reference Docker can pull, e.g. ghcr.io/you/app:1.2.0` | `image_ref` is not an image reference. |
| `422` | `repo_url is for apps that build from git` | An image app was sent a repository field. |
| `422` | `The health check path must start with / and be a plain URL path` | `health_check_path` is not a path. |
| `429` | `{"error": "rate_limited", "message": "Too many apps created in the last hour. Wait a while and try again.", "retry_after_seconds": 3600}` | You created 20 apps in the last hour. |

An organization's route also answers `403` with `Admin access required` for a member who is not an owner or admin. [Apps limits](/docs/apps/limits/#requests) lists the other rate limits.

## API

- `POST /api/v1/client/apps`: Create an app and, unless deploy is false, its first deployment (https://www.coritan.com/docs/api/reference/client/apps/#op-post-api-v1-client-apps)
- `POST /api/v1/orgs/{org_slug}/apps`: Create an app and, unless deploy is false, its first deployment (https://www.coritan.com/docs/api/reference/organizations/organization-apps/#op-post-api-v1-orgs-org-slug-apps)
