Use the Coritan CLI
Deploy a directory from your computer or from CI, promote and roll back releases, pull variables, read logs and add domains from a terminal.
The Coritan CLI, coritan, works with App Deployment from a terminal. It deploys a directory without a git push and follows its build, promotes a preview, rolls back, writes a deployment's variables to .env.local, reads logs and adds custom domains. It runs on your computer and in CI, and needs only Node.js.
Before you begin
Section titled Before you begin- Install Node.js 18 or newer.
- Have a web service built from git, a static site or a hybrid site to deploy to (Order a deployment). The other commands also work with a web service that runs an image. A game server or a database has no releases to deploy, and you manage it on its own page instead (Use the console and power controls).
- The CLI signs in with an API key, so it works with your own account's deployments. No key can reach an organization's (What no key can do).
Install the CLI
Section titled Install the CLIThe CLI is not on npm yet. Ask support for a copy: it is the folder sdk/cli. Pack it, then install the package that makes:
cd sdk/cli && npm pack
npm i -g ./coritan-cli-0.1.0.tgz
coritan --version
Sign in
Section titled Sign in- Create an API key on the API keys tab of Settings (Create a key). To deploy with it, tick at least one Write permission.
- Run
coritan loginand paste the key when it asks. It is not shown as you type.
The CLI checks the key with the API and saves it in your configuration directory, readable by you alone: ~/.config/coritan on Linux (or $XDG_CONFIG_HOME/coritan), ~/Library/Application Support/Coritan on macOS and %APPDATA%\Coritan on Windows. CORITAN_CONFIG_DIR names another directory. A key can also be piped in, as in coritan login < key.txt.
coritan whoami shows the key the CLI uses, by its first and last characters, with your plan and the linked deployment. coritan logout deletes the saved key. The key itself keeps working until you revoke it (Revoke a key).
While CORITAN_API_KEY is set, every command uses it, coritan login checks it instead of asking for a key, and coritan logout leaves it alone.
A key with only Read permissions can list releases, variables and domains, and read logs. Deploying, promoting, rolling back, changing domains and pulling variable values take a key with a Write permission.
Link a directory
Section titled Link a directoryIn your project's directory, run coritan link and choose the deployment, or name it by its name, slug or ID:
coritan link my-site
The link is the file .coritan/project.json. It holds the deployment's ID and name, and no secret. The CLI writes .coritan/.gitignore beside it, so git leaves the link out without a change to your own .gitignore.
Every command run in the directory, or in one below it, acts on the linked deployment. --deployment <name> or CORITAN_DEPLOYMENT names another, and coritan unlink removes the link.
Deploy
Section titled Deploy- In the linked directory, run
coritan deployfor a preview of the branch git has checked out, orcoritan deploy --prodfor production. - The CLI packs the directory, uploads it and prints the build log as it is written. The directory is built as a push would be, in a build container of its own (How a release is built), with the deployment's build settings and the variables of the environment it goes to. A root directory in the build settings is looked for inside the upload, so for a repository that holds several apps, link and deploy from its top directory.
- When the release is live, the CLI prints the addresses it answers at, one a line.
The addresses are the only thing printed to standard output, so a script can keep them:
url=$(coritan deploy --prod)
- What goes in an upload
- Every file in the directory except what
.gitignoreand.coritanignorefiles list, at any depth..coritanignorewins, so!dist/in it uploads a build output that git leaves out.node_modules/,.env.localand.env.*.localare left out unless an ignore file brings them back with!, and.gitand.coritannever go. A.envfile goes unless an ignore file lists it, so keep secrets out of it: put them in the deployment's variables, or in.env.local. A name holding a control character, such as theIconfile macOS writes for a folder's icon, is left out and named, because the API refuses an archive that holds one. So is a name that is not UTF-8.coritan deploy --dry-runlists what would go and uploads nothing. - How much
- 100 MiB packed and 1 GiB unpacked, in 100,000 files at most. The CLI checks before it sends anything, and names the largest files when an upload is too big.
- Where it goes
- Without
--prod, a preview of--branch <name>, or of the branch git has checked out. The production branch is only ever released with--prod. Previews come with the Pro plan and above. - The message
-m "Fix the header"sets the message shown with the release. Without it, the release shows the last commit's subject.- Following the build
--no-waitprints the release's ID and stops, and--jsonprints the release and its addresses as JSON. Ctrl+C stops following; the release carries on.
Promote and roll back
Section titled Promote and roll backcoritan releases # newest first, with the IDs the other commands take
coritan promote c0ffee00 # a ready preview to production, without building it again
coritan rollback # production back to the release before the current one
coritan rollback a11ce000 # or to the release you name
Name a release by its ID or by its first characters: the eight that coritan releases shows, or four at the least. promote and rollback ask before they change production, and --yes answers for a script. They do what Promote to production… and Roll back to this… do on the Releases tab (Deploy, promote and roll back releases).
Pull variables
Section titled Pull variablescoritan env pull # development values to .env.local
coritan env pull -e production --force # production values, over the file there
coritan env pull .env.preview.local -e preview --branch feature-x
coritan env ls # keys and where they apply, no values
env pull writes the variables a release of that environment reads, env groups included, to .env.local in the linked directory, or to the file you name. It writes the development environment unless -e names another, and it never overwrites a file without --force. The file is readable by you alone, and the CLI warns you when git would commit it.
Secret values never leave Coritan: the file names their keys at the top, for you to fill in by hand when you need them. Environments and variables explains environments, secrets and env groups.
Read logs
Section titled Read logscoritan logs # the last 100 lines, oldest first
coritan logs --since 2h -q timeout # two hours back, lines holding "timeout"
coritan logs -f -p worker # follow the worker process until Ctrl+C
coritan logs -f -n 0 # follow, printing only new lines
coritan logs --instances # the instances, with the IDs --instance takes
coritan logs --json | jq -r .message
--since and --until take a time, such as 2026-09-27T10:00:00Z, a Unix time, or how long ago, such as 30s, 15m, 2h or 7d. --instance and -p narrow the lines to one instance or one process. coritan logs --instances lists each instance's ID, process, location, state, release and last line.
-n says how many lines to print: 100 when left out, and up to 10,000, which the CLI reads 1,000 at a time. With -f it is how many lines each instance starts with, at most 200, and -f -n 0 prints only new lines. -f does not go with --since or --until, because it starts from each instance's latest lines.
A live tail lasts at most 15 minutes, and the CLI opens the next one at once. When the connection drops, it connects again after a pause that grows each time, and leaves out the lines it has printed already. When it cannot tell where it left off, it prints (Lines may be missing here.).
--json prints each line as the API's JSON, one object a line, so jq -r .message prints the text alone. Logs and metrics says how long lines are kept.
Manage domains
Section titled Manage domainscoritan domains # the platform address and your domains
coritan domains add shop.example.com # prints the records to publish
coritan domains verify shop.example.com # checks the TXT record
coritan domains rm shop.example.com
A custom domain gets no traffic until it is verified. Publish the TXT record that domains add prints, point the name at the deployment with the CNAME record, then run domains verify (Add a custom domain).
Deploy from CI
Section titled Deploy from CI- Create an API key for the job alone, and keep it in your CI system's secrets.
- Keep the CLI's package where the job can read it, such as in your repository.
- In the job, set
CORITAN_API_KEYfrom the secret andCORITAN_DEPLOYMENTto the deployment's name or ID, install the CLI and deploy:
npm i -g ./tools/coritan-cli-0.1.0.tgz
export CORITAN_API_KEY="$CORITAN_KEY_FROM_YOUR_SECRETS"
export CORITAN_DEPLOYMENT=my-site
url=$(coritan deploy --prod)
echo "Deployed to $url"
The CLI uses CORITAN_API_KEY without saving it, and never waits for an answer when it is not run at a terminal: a question becomes an error that names the option answering it, such as --yes or --deployment.
--json on coritan releases and coritan domains prints the API's answer as it came, {"releases": [...]} and {"domains": [...], "limits": {...}}, so a script reads the newest release's ID as .releases[0].uuid.
| Exit code | Means |
|---|---|
0 |
Done: the release is live, or the file is written. |
1 |
It failed or the API refused: the release failed, the key was refused, or a domain is not verified yet. |
2 |
The command was wrong: an unknown option, a missing value, or a question with no terminal to ask it at. |
130 |
Stopped with Ctrl+C while following a deploy; the release carries on. coritan logs -f ends with 0. |
| Environment variable | What it does |
|---|---|
CORITAN_API_KEY |
The API key to use in place of the saved one. |
CORITAN_DEPLOYMENT |
The deployment, by name or ID, in place of the link. |
CORITAN_CONFIG_DIR |
Where coritan login saves the key. |
CORITAN_DEBUG |
Set to 1 to print where a fault in the CLI happened. |
NO_COLOR, FORCE_COLOR |
Print without colour, or with colour when not at a terminal. |
Result
Section titled Resultcoritan deploy ends by printing the release's addresses, and the release is on the deployment's Releases tab with its build log.
Troubleshooting
Section titled TroubleshootingYour Free plan does not include preview deployments. To use it, upgrade to Pro.- Previews come with the Pro plan and above. The CLI prints where to change your plan, or release to production with
coritan deploy --prod. main is the production branch of my-site, so deploying it releases to production.- The CLI releases production only when you say so. Add
--prod, or deploy another branch as a preview with--branch <name>. Say where this deploy goes: --prod for production, or --branch <name> for a preview of that branch.- The directory is not in a git checkout with a branch, so the CLI cannot tell which preview you mean. Name the branch, or add
--prod. This API key can only read. Exporting variable values takes a key with a write permission.- Create a key with a Write permission. Run
coritan loginwith it, or, when the key is inCORITAN_API_KEY, put the new key in the variable: the CLI uses the variable over a saved key. The CLI's hint says which. Deploying, promoting, rolling back or changing domains with a read-only key answersThis API key can only read. Create a key with a write permission to make changes., and the fix is the same. The API did not accept the API key. It may have been revoked, or it has expired.- The key was revoked or has expired. The CLI says where the key came from, with
CORITAN_API_KEY holds it: set it to a key that works.or a hint to runcoritan loginwith a key that works, and where to create one.coritan loginsaysThe API did not accept this key: it may have been revoked, or it has expired. Nothing was saved. - A message that ends
runs an image, which is not deployed from a directory. - A deployment that runs an image is released with a new image, not a directory. The CLI prints the deployment's page, where you start one (Start a release).
- A message that ends
is a server, which is not deployed from a directory. - A server or a database (
is a database, ...) runs its software from the catalogue, so nothing is uploaded to it.coritan openopens its page.coritan logspoints at its Console tab,coritan domainsat its Ports tab andcoritan envat its Settings tab, since its logs, addresses and startup variables are there. - A message such as
My Site builds from the directory apps/web, which is not in the upload from /home/me/repo/apps/web. - The deployment builds from a directory of its repository, and looks for that directory inside the upload. Deploy the directory that holds it: the CLI prints the command, such as
coritan deploy ../.. --deployment my-site --prod. To make plaincoritan deploydo that from anywhere in the repository, runcoritan unlinkin that directory andcoritan linkat the top. The CLI checks this before it packs anything, so it also catches a root directory that your ignore files leave out, andcoritan linksays so when you link a directory that does not hold it. 5 live tails are open already. Close one first.- Each
coritan logs -fholds a live tail, and an account can hold five at once, whichever keys opened them. Stop another, or wait for one to end. - A message that ends
is gone: it was deleted, or this key no longer reaches it. - The deployment was deleted while
coritan logs -ffollowed it. It exits with1. - The upload is too large
- Add what the deploy does not need to
.coritanignore, such as test data or local build caches, and check withcoritan deploy --dry-run. The upload could not be stored, so this release was not built. Deploy it again.- The API took the upload but could not store it, and the release it made is marked failed. The CLI says when to try again, such as
Try again in 30 seconds. That hostname is in use on the platform.- Another deployment, yours or another account's, has verified that hostname, or added it in the last 72 hours without verifying it. The API does not say whose. An unverified name is released after 72 hours.
That hostname is already added to this deployment.means it is on this one already.
Related
Section titled Related- Deploy from a git repository builds a release for each push, with no upload.
- Host a static site or a hybrid site explains what a static build should write.
- Manage API keys covers what a key can do and how to revoke one.
With the API
Section titled With the APIcoritan deploy is one request: POST /api/v1/client/deployments/{uuid}/uploads, a form with the archive in file and, beside it, branch, message and environment (production or preview). Left out, environment is preview for a branch other than the production branch. The archive is a gzipped tar of the directory:
tar -czf site.tar.gz -C ./site .
curl -X POST https://api.coritan.com/api/v1/client/deployments/$DEPLOYMENT/uploads \
-H "Authorization: Bearer $CORITAN_TOKEN" \
-F "file=@site.tar.gz" \
-F "branch=main" \
-F "environment=production"
It answers 201 with the release, which GET /releases/{release} then follows as it builds. An organization's deployment takes the same form at /api/v1/orgs/{org_slug}/deployments/{uuid}/uploads, from an owner or an admin who signs in, since no API key reaches an organization.
A deployment that runs an image answers 409 with This deployment runs an image. Release an image reference instead of an upload. A preview on a plan without previews answers 402, an archive over the sizes above 413 with too_large, and an archive that cannot be unpacked, or that holds a name with a control character, 422 with invalid_archive.
API operations on this page
| Method | Path | What it does |
|---|---|---|
POST | /api/v1/client/deployments/{deployment_uuid}/uploads | Upload release |
POST | /api/v1/orgs/{org_slug}/deployments/{deployment_uuid}/uploads | Upload release |