Guides
Building and deploying
What happens between pushing a commit and serving it, and every lever you have over that process.
What triggers a build
- A push to the tracked branch, when automatic deploys are on (the default).
- The console — the Deploy button on the app page.
- The CLI —
codaracloud deploy <app> --source. - The API, for CI systems and automation.
Turn automatic deploys off per app if you would rather release manually. The setting lives on the app’s settings page, or use --manual-deploys when creating from the CLI.
Watch paths
In a monorepo, watch paths stop unrelated changes from rebuilding everything. They are glob patterns relative to the repository root, and a push that matches none of them is recorded as a skipped deploy rather than being silently dropped.
$ codaracloud apps update api \ --client my-workspace \ --watch-path "services/api/**" \ --watch-path "packages/shared/**"Watch paths fail open
One repository, several apps
The same repository and branch can back several apps across different workspaces, projects and environments. A single push enqueues a build for every app that matches — which is exactly how you keep staging and production on the same branch, and why watch paths matter in a monorepo.
How your image is built
Codara inspects the build context and picks a strategy in a fixed order. The first match wins:
| Order | Condition | Strategy |
|---|---|---|
| 1 | A file named exactly Dockerfile at the build root, or an explicit Dockerfile path | Your Dockerfile |
| 2 | nixpacks.toml at the build root | Nixpacks |
| 3 | A recognised language manifest | Railpack (the default buildpack) |
| 4 | Static assets only | A generated nginx image |
| 5 | Nothing recognisable | The build fails with a detection error |
Dockerfile detection is case-sensitive
Dockerfile at the root of the build context. A lowercase dockerfile, or one in a subdirectory, will not be picked up — your repo will fall through to a buildpack instead. Set the Dockerfile path explicitly if yours lives anywhere else.Nixpacks is opt-in, not the default
nixpacks.toml is built by Railpack, not Nixpacks. Add the file only if you specifically want Nixpacks.Root directory
Set a root directory to build from a subdirectory. Everything — Dockerfile detection, buildpack detection, the build context — is resolved relative to it.
Build arguments versus runtime variables
These are two separate channels and mixing them up is a common source of confusion.
| Build arguments | Environment variables | |
|---|---|---|
| Available during build | Only to your own Dockerfile, through its ARG instructions | No |
| Available at runtime | No | Yes |
| Suitable for secrets | Never | Yes |
| Limits | Up to 32 values, 1024 characters in total | Up to 65536 characters per value |
Never put a secret in a build argument
Build arguments reach a build only through a Dockerfile you wrote: each one fills the ARG instruction with the same name. Builds without your own Dockerfile (Railpack, Nixpacks and static sites) do not receive them today, even though you can still set them on the app.
If your framework needs a public value at build time, such as an API base URL baked into a client bundle, you have two options:
- Commit it to the file your framework reads at build time. A Next.js app reads
NEXT_PUBLIC_values from a committed.env.production, and that works with Railpack. - Build with your own Dockerfile, declare
ARG NAME(andENV NAME=$NAMEif the build tool reads it from the environment), and set the value as a build argument.
Either way the value ends up in the image or the client bundle, so use this only for values you would publish. Anything else belongs in environment variables.
The rollout
A finished build does not mean a finished deploy. Codara pushes the image, then rolls it out and waits for the new pods to actually become healthy before marking the release live.
By default the rollout is gradual: new pods must come up healthy before old ones are retired, so there is no downtime. An app with a volume attached uses a stop-then-start rollout instead, because the disk can only be mounted by one pod at a time — expect a short gap on every deploy for those.
A failed replacement preserves the healthy release
Health checks
Configure a health check path on the app and Codara uses it to decide both whether a pod is alive and whether it is ready for traffic. Without one, a container that starts but never becomes usable can still be rolled out. A cheap /health endpoint that returns 200 is worth adding.
Pre-deploy commands
A pre-deploy command runs once in the new image before any traffic moves to it. This is where database migrations belong: if the command fails, the release is abandoned and your current version keeps serving.
npm run migrate:deployRolling back
Rollback re-releases an earlier deploy’s image. It does not rebuild, so it is fast and produces exactly the bytes that were running before.
$ codaracloud deploys list my-api$ codaracloud rollback my-api --to-deploy <deploy-id>The rollback is recorded as a new deploy pointing at the old image, so your history stays honest about what was running when.
Some older deploys need a rebuild
codaracloud deploy my-api --commit <sha>.Promoting between environments
Promotion moves the exact image you tested in one environment into another, with no rebuild. The target keeps its own environment variables, domains and scaling — only the image changes.
$ codaracloud promote my-api \ --from-deploy <deploy-id> \ --from-env staging \ --to-env productionSee Environments for how to structure this.
Cancelling a build
A queued or in-flight build can be cancelled up until the point it is promoted. The currently serving release is unaffected.
$ codaracloud deploys cancel my-api <deploy-id> --confirmDeploying a prebuilt image
An app can point at an existing container image instead of a repository, which suits third-party software and images built elsewhere.
$ codaracloud apps image my-app ghcr.io/acme/my-app:v1.4.2Passing the same reference again re-pulls it, which is how you refresh a floating tag like :latest. For a private registry, configure credentials first:
$ echo "$REGISTRY_TOKEN" | codaracloud apps registry set my-app \ --username acme-ci \ --password-stdinThe password is only ever read from stdin, and credentials are never returned by the API.
Build limits worth knowing
| Limit | Value |
|---|---|
| Maximum build duration | 30 minutes, after which the build is failed |
| Concurrent builds | 4 at a time across the platform — further builds queue and report their position. Each running build also reserves 2.5 vCPU and 4.5 GiB of your plan’s hard ceiling for apps and builds. |
| Build log retention | 24 hours. After that the logs endpoint returns empty. |
| Build retries | None — a failed build is final until you trigger another |
Build logs are not archived
Plan limits can block deploys
Each plan includes a number of build starts per calendar month (UTC), and failed builds count. Once they are used up, new builds cannot start until next month; running apps are unaffected. Other requests past a plan limit are refused, usually with 402 plan_limit_exceeded, which names the limit. A cancelled or expired subscription allows no new deploys, and its running workloads are paused; data is kept. See Plans and capacity.
Last updated
