Deployment (Hokusai)
Orbit deploys to Artsy's Kubernetes clusters with Hokusai, the same tooling used by most Artsy services. This page covers the files in the repo, the CI pipeline, and the one-time setup an operator needs to do.
What's in the repo
| Path | Purpose |
|---|---|
Dockerfile | Builds the production image: Node 22 (Alpine), installs deps with the vendored Yarn 4, runs prisma generate + next build, runs as the non-root deploy user. |
.dockerignore | Keeps the build context small (no node_modules, .next, docs, env files, …). |
scripts/load_secrets_and_run.sh | Container entrypoint. Sources the fortress-provided $SECRETS_FILE (if set) into the environment, then execs the command (yarn start). |
hokusai/config.yml | Project name, the pre-deploy: yarn prisma:deploy migration hook, and the shared template-config-files var source. |
hokusai/build.yml / development.yml / test.yml | docker-compose files for local hokusai build / dev / test. |
hokusai/staging.yml / production.yml | Kubernetes manifests (Deployment, HPA, Service, Ingress, example CronJob) for each environment. |
.circleci/config.yml | CI pipeline: test → build/push image → deploy staging (on main) → deploy production (on release). |
.tool-versions / .nvmrc | Pin the Node version for asdf / nvm. |
How it runs in the cluster
- The app listens on port 8080 (
PORTis set in the manifest; Next.js'yarn starthonours it). - Kubernetes health-checks the app with a readiness probe against
/api/status(the endpoint insrc/pages/api/status.page.ts). - Secrets are delivered by the fortress init container, which writes them to a shared
/secretsvolume;secrets-configsetsSECRETS_FILE, andload_secrets_and_run.shsources that file before the app starts. This is why the entrypoint script is required — do not remove it.
Database migrations
Orbit uses Prisma/Postgres against an external (RDS) database, not an in-cluster one. Schema migrations run automatically before each rollout via the Hokusai pre-deploy hook in hokusai/config.yml:
pre-deploy: yarn prisma:deployprisma migrate deploy applies any pending migrations in prisma/migrations/. Because it runs as a one-off pre-deploy step (not on every pod start), it's safe with multiple replicas.
Required secrets
Set these in citadel/fortress for both staging and production (see .env.example for descriptions):
DATABASE_URLNEXTAUTH_URL(the public URL of the environment) andNEXTAUTH_SECRETCLIENT_APPLICATION_ID/CLIENT_APPLICATION_SECRET(Gravity OAuth)GRAVITY_URLandPUBLIC_GRAVITY_URLORBIT_SERVICE_TOKENS(optional — read-only bearer tokens for headless clients such as release-lookout)
One-time setup
An operator with cluster access does this once (see the Artsy Hokusai playbook):
hokusai setup --project-type nodejscreated the scaffolding (already committed). Adjust the manifests as above.- Create the ECR repository and push the first image (
hokusai registry push/hokusai build). - Create the citadel/fortress secret set with the variables listed above.
- The Horizon
project_idin.circleci/config.yml(282) gates production releases via thehorizon/blockjob on thereleasebranch. - Wire the
hokusaiCircleCI context and open the pipeline.
Once set up, the flow is: merge to main → CI builds, pushes, and deploys to staging; promote to the release branch → CI deploys to production (gated by the Horizon block).

