Deployment
Deployment

Go-live checklist

The things that are cheap to check now and expensive to discover later. Everything here has bitten a real deployment.

Most of this is machine-checkable. Run grit doctor first and let it find what it can — then work through the rest, which needs a human who knows what the app is for.

grit doctor

Secrets

The single most common way a hobby deploy becomes an incident.

JWT_SECRET is unique to this environment

Not the value from .env.example — that string is identical in every Grit project ever generated. Staging and production must differ, or a token minted in staging is valid in production.

No secret is a build argument

Build logs are retained, often readable by more people than the container environment, and frequently shipped to a third-party CI provider.

Nothing sensitive is in a NEXT_PUBLIC_ variable

Those are compiled into JavaScript that every visitor downloads. Grep the built output before launch: a leaked key here is public the moment the page loads.

.env is not committed

Check the history, not just the working tree. A rotated key is only rotated if the old one is dead.

Access

CORS_ORIGINS lists exact origins

No wildcard. With credentialed requests a wildcard is both a security hole and rejected by browsers.

The database is not reachable from the internet

The development compose file publishes Postgres on a host port so you can attach a GUI. The production one must not. Confirm from outside the network, not from the server.

Studio, Pulse and Sentinel dashboards are protected

GORM Studio at /studio browses every table. Pulse and Sentinel expose traffic and configuration. All three must be behind auth, an IP allowlist, or switched off in production.

The default admin account is gone or has a new password

admin@example.com / admin123 is in the seeder of every generated project, and in these docs.

Data

Migrations ran as an explicit step

Grit does not auto-migrate in production. A process that rewrites the schema on every boot is a bad idea when the platform restarts it for its own reasons.

Backups are configured AND a restore has been tested

An untested backup is a hypothesis. Restore into a scratch database and count the rows — that is the only thing that turns it into a fact.

Uploads go to object storage, not local disk

Any platform that can move or rebuild your container will lose local files. This includes every PaaS on the previous pages.

Operations

The health check points at /api/health

Not /. A platform checking the wrong path either cycles a healthy machine forever or reports a deploy that never finishes.

You know how to roll back

Before you need to, not during. On a plain VPS that means keeping the previous binary; on a PaaS it means having actually clicked the button once.

Logs go somewhere you can search

Container stdout that nobody collects is not logging. Confirm you can find a specific request from an hour ago.

Someone is told when it breaks

An uptime check hitting /api/health from outside your infrastructure. Finding out from a customer is the expensive way.

One thing this list cannot check

Whether anyone other than you can deploy it. Write down the steps — where it runs, how to get a shell, how to restore the database, who pays the bill. A deployment only one person understands is an outage waiting for that person to be unavailable.