Docs
Docs / Guides / Deployment

Deployment

This guide walks through taking a build from your local machine to a production environment. It covers the prerequisites, the required environment variables, the deploy itself, and how to roll back if something goes wrong.

Prerequisites

Environment variables

The service reads its configuration from the environment at startup. The most important variables are listed below. Anything not set falls back to the defaults in the configuration reference.

VariableRequiredDescription
APP_ENVYesproduction, staging, or development
DATABASE_URLYesConnection string for the primary database
SECRET_KEYYesUsed to sign sessions and tokens. Must be at least 32 bytes.
PORTNoPort to listen on. Defaults to 8080.
LOG_LEVELNodebug, info, warn, or error. Defaults to info.

Deploy steps

1. Run database migrations

Run migrations before starting the new version. Migrations must be backward compatible with the version currently running so that a rolling deploy does not fail.

$ ./bin/app migrate up --env production

2. Start the new version

$ ./bin/app serve --env production --port 8080

Or, if you run under a container orchestrator, push the image and update the deployment:

$ docker build -t registry.example.com/app:1.8.0 .
$ docker push registry.example.com/app:1.8.0
$ kubectl set image deployment/app app=registry.example.com/app:1.8.0

3. Verify health

Wait for the health check to pass before routing traffic to the new instances.

$ curl -fsS https://app.example.com/healthz
{"status":"ok","version":"1.8.0"}
Tip: Most load balancers wait for /healthz to return 200 before marking an instance as healthy. You do not need to add extra delay.

Rolling back

If the new version misbehaves, redeploy the previous image. Database migrations are not reversed automatically.

$ kubectl rollout undo deployment/app
Warning: Do not run migrate down in production unless you have confirmed that no data will be lost. Rolling back a destructive migration can delete rows or columns permanently.

Troubleshooting

The service exits immediately on startup

Check that SECRET_KEY is set and at least 32 bytes long. The service refuses to start in production mode without it.

Health checks fail after deploy

Confirm that DATABASE_URL is reachable from the new instance. Network policies and security groups are the most common cause.

Requests return 502 from the load balancer

The application is probably listening on a different port than the one the load balancer targets. Make sure PORT matches the target group configuration.