Configuration
TinyCMS uses backend environment variables for secrets and deployment settings, plus a complete JSON file for runtime options. Frontend secrets are never needed for administrator setup.
Environment variables
Start from apps/backend/.env.example for the full list.
| Variable | Purpose |
|---|---|
DB_FILE_NAME | Database URL; use a persistent local file: URL for the documented backup workflow |
BETTER_AUTH_SECRET | Stable authentication secret; preserve separately for recovery |
SETUP_TOKEN | Temporary bootstrap secret, at least 32 random characters; remove after setup |
BETTER_AUTH_URL | Public backend URL used for authentication and email links |
FRONTEND_ORIGIN | Allowed frontend origin and email return origin |
NODE_ENV | Set to production; frontend serving also requires server.serveFrontend |
PORT | Backend listener port; defaults to 3000 |
APP_CONFIG_FILE | Optional complete JSON configuration path; otherwise backend config.json |
JOB_TRIGGER_TOKEN | Optional secret for externally triggered jobs; at least 32 characters |
WEBHOOK_ENCRYPTION_KEY | Base64-encoded random 32-byte key for stored webhook signing secrets |
For same-origin production, set both URL variables to the same public HTTPS origin, such as https://cms.example.com. Use the actual domain, not the backend's loopback address.
Generate independent secrets using openssl rand -hex 32. Generate the webhook encryption key with openssl rand -base64 32. Preserve existing keys during upgrades and restoration.
Transactional email
For Resend, set EMAIL_PROVIDER=resend, RESEND_API_KEY, and RESEND_FROM_EMAIL. Both Resend values are required in production.
For SMTP, set EMAIL_PROVIDER=smtp, SMTP_HOST, and SMTP_FROM_EMAIL. SMTP_PORT defaults to 587. Set both SMTP_USER and SMTP_PASSWORD when authentication is required. SMTP_SECURE accepts true or false; when omitted, it is true for port 465 and false otherwise.
Verify delivery to a real account before relying on setup, verification, or password recovery.
Complete production JSON example
Save this as /etc/tinycms/config.json for the deployment layout in this manual. Adjust paths and limits to your installation. It includes required sections; optional processing settings use application defaults.
json
{
"delivery": { "apiKeyUsageIntervalSeconds": 60 },
"session": {},
"paths": {
"profileImages": "/var/lib/tinycms/profile-images",
"contentBackups": "/var/lib/tinycms/content-backups",
"frontendDist": "/srv/tinycms/app/apps/frontend/dist"
},
"server": {
"serveFrontend": true,
"shutdownAllowlist": [],
"listenAddress": "127.0.0.1"
},
"backup": { "directory": "/var/backups/tinycms" },
"media": {
"directories": {
"image": "/var/lib/tinycms/media/images",
"document": "/var/lib/tinycms/media/documents",
"video": "/var/lib/tinycms/media/videos",
"audio": "/var/lib/tinycms/media/audio",
"cache": "/var/cache/tinycms",
"staging": "/var/lib/tinycms/staging",
"quarantine": "/var/lib/tinycms/quarantine"
},
"maxBytes": {
"image": 26214400,
"document": 104857600,
"video": 104857600,
"audio": 26214400
},
"imageMaxDimension": 4096,
"audioEnabled": false,
"videoEnabled": false,
"malwareScan": {
"mode": "disabled",
"socketPath": "/run/clamav/clamd.ctl",
"timeoutMs": 30000
},
"ffprobePath": "ffprobe",
"ffmpegPath": "ffmpeg",
"upload": {
"maxFiles": 10,
"maxBytes": 104857600,
"requestBytes": 105906176
}
},
"jobs": { "schedules": "automatic", "webhooks": "automatic" }
}APP_CONFIG_FILE selects the entire configuration, not a partial override. Unknown or invalid settings fail validation. Relative configuration and storage paths resolve from the process working directory; absolute production paths avoid ambiguity.
Frontend hosting
Configure frontend hosting in JSON alongside the existing path settings. Environment variables remain for secrets and deployment settings; APP_CONFIG_FILE selects the complete configuration for each deployment.
| Setting | Default | Purpose |
|---|---|---|
server.serveFrontend | true | Serve built frontend files and the Vue route fallback when NODE_ENV=production |
paths.frontendDist | ../frontend/dist in the supplied config | Frontend build directory, relative to the backend working directory or absolute |
Keep server.serveFrontend: true when the backend should serve the frontend, including when a reverse proxy forwards the entire site to it. Set it to false when Nginx or another host serves the frontend files. The flag must be a JSON boolean; omitted values default to true for existing configurations. Development always uses the separate frontend dev server.
When disabled, the backend returns TinyCMS API at / and 404 for frontend paths. API, auth, health, media, and profile-image routes continue to work. A frontend build does not need to exist on the backend host, but keep paths.frontendDist configured: storage validation still reserves this path to keep private storage separate from public assets.
For reverse-proxy hosting, serve only the frontend build directory, use an index.html fallback for Vue routes, and forward /api, /resources, /profile-images, and /health to the backend. Keep browser requests on the same public origin; no VITE_API_URL override is needed. See deployment for a complete alternative Nginx server block.
Loading settings
The backend dev script loads its workspace .env. Backup workspace scripts load .env if present. The production start script runs node dist/index.js and does not load .env itself. Inject variables through your service manager or explicitly use Node's --env-file option.
The deployment service uses systemd's EnvironmentFile. Manual production maintenance commands in this manual use node --env-file=/etc/tinycms/backend.env and must be run from the backend workspace.
Restart after configuration changes. Keep the complete JSON, environment file, original auth secret, webhook encryption key, and external credentials in a separate secure recovery store: deployment backups exclude them.