Environment Variables
Every variable a Crudy deployment reads.
The backend reads its configuration from environment variables and validates them at boot. Missing or weak secrets cause the process to exit before the server starts listening.
Required at boot
The framework's assertSecretsHardened check runs first. It enforces these and any module-declared secrets.
| Variable | Required | Notes |
|---|---|---|
JWT_SECRET | yes | At least 32 characters. Must not match known defaults (changeme, password, secret, admin, ...). Must have at least 8 unique characters of entropy. |
LICENSE_FILE | yes | Path to the license.lic file Crudy issued for your deployment. Read once at boot. |
LICENSE_PUBLIC_KEY or LICENSE_PUBLIC_KEY_FILE | yes | The verification key Crudy shipped alongside your license. Inline PEM or a path. |
If any check fails the backend logs the failures with the [secrets] prefix and exits.
Never deploy with a placeholder secret. The check rejects common default values (including changeme, change-this-to-a-long-random-secret-in-production, postgres, admin, test, dev) and any string under 32 characters or with low entropy.
Database
| Variable | Default | Notes |
|---|---|---|
DB_HOST | localhost | PostgreSQL hostname. In the generated compose file this is postgres. |
DB_USER | required | PostgreSQL role used by the backend. |
DB_PASSWORD | required | Password for that role. |
DB_NAME | required | Database name. |
POSTGREST_URL | http://localhost:3002 | Internal PostgREST URL. Never exposed publicly. |
POSTGREST_DB_PASSWORD | required | Password for the authenticator role used by PostgREST. |
The generated docker-compose.yml reads DB_USER, DB_PASSWORD, DB_NAME, and POSTGREST_DB_PASSWORD from your .env.
Admin account
| Variable | Default | Notes |
|---|---|---|
ADMIN_EMAIL | admin@localhost | Global admin user created on first boot with a random unusable password. Run crudy admin reset to set a password. |
Do not set ADMIN_EMAIL=admin@example.com for the global admin. That email is used by dev seeds for an org-scoped admin and conflating the two creates a misleading permission state.
Network and CORS
| Variable | Default | Notes |
|---|---|---|
CORS_ORIGIN | http://localhost:3001 | Comma-separated list of allowed origins for the API. |
BACKEND_PORT | 3000 | Host port the backend container publishes. |
FRONTEND_PORT | 3001 | Host port the frontend container publishes. |
NEXT_PUBLIC_API_URL | http://localhost:3000 | URL the frontend uses to reach the backend. Baked into the build because of the NEXT_PUBLIC_ prefix. |
Operational toggles
| Variable | Default | Notes |
|---|---|---|
NODE_ENV | required by Docker images | development or production. |
DISABLE_RATE_LIMIT | unset | Set to true only for local load testing. Never in production. |
Module-declared secrets
A module can declare additional required secrets in its BackendModule.requiredSecrets array. The framework adds them to the boot-time check:
requiredSecrets: [
{ name: 'SMTP_PASSWORD', minLength: 16, description: 'SMTP relay password' },
]If the module is wired into the app, the variable must be present at boot. The same length and entropy checks apply.
Where to put values
- Local dev:
.envin the app root, loaded bydocker composeand by the generatedMakefiletargets. - Production: your secrets manager. Mount values into the backend container.
- Never commit
.envfiles to source control. The framework ships.env.exampleas the documented template.
Verifying
After setting variables, make health confirms the backend is up and reports db: connected. If the backend fails to start, its logs (make dev-logs or docker logs <container>) will show the [secrets] failures or the license verification error.