Extending
Deployment
One container, one volume, and a readiness probe is most of what a Yatta deployment needs.
Docker
docker build -t yatta .docker run -p 4000:4000 \ -e NODE_ENV=production \ -e STORAGE_SECRET="$(openssl rand -hex 32)" \ yattaThe image runs as the non-root bun user, installs --production dependencies from a frozen lockfile, and ships a HEALTHCHECK pointed at /healthz.
Persist the data
SQLite files and uploaded files live on disk. Without a volume they are lost when the container is replaced.
docker run -p 4000:4000 \ -v yatta-data:/app/Database \ -v yatta-uploads:/app/storage/uploads \ -e STORAGE_SECRET="$(openssl rand -hex 32)" \ yattaNote
On a single node this is sufficient. If you run more than one container, do not share a SQLite file across nodes — move storage to S3 and put a real database behind
yatta/db.Cluster mode
One process per core behind SO_REUSEPORT. SQLite is configured for exactly this — WAL, busy timeout, and schema creation under BEGIN IMMEDIATE with retries.
bun run cluster# single processdocker run -e YATTA_CLUSTER_MODE=false yattaOrchestrator probes
livenessProbe: httpGet: { path: /healthz, port: 4000 } initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: httpGet: { path: /readyz, port: 4000 } initialDelaySeconds: 5 periodSeconds: 10 terminationGracePeriodSeconds: 20 # longer than the 10s drainWarning
terminationGracePeriodSeconds must exceed the drain window. If the orchestrator sends SIGKILL first, in-flight work is lost and the graceful shutdown never completes.Production checklist
NODE_ENV=productionsetSTORAGE_SECRETset to a real random value — startup fails otherwiseAUTH_SECRETset, not left at its development defaultDatabase/andstorage/uploadson persistent volumes- Storage driver switched to
s3if you run more than one node - Grace period longer than the 10-second drain
/healthzas liveness,/readyzas readiness
What to watch
curl localhost:4000/readyz | jq '.topology, .inFlightTasks' # jobssqlite3 Database/jobs.db \ "SELECT state, COUNT(*) FROM _yatta_jobs GROUP BY state;"A rising dead count means handlers are failing after retries. The DLQ API lists them for replay — see Jobs.