Environment Variables — Complete Reference
.app_env file format (production)
In production (Docker Compose), variables are loaded from a .app_env file:
# All values in double quotes — mandatory
PG_HOST="postgres"
PG_PORT="5432"
PG_DATABASE="racines"
PG_USER="postgres"
PG_PASSWORD="your_secure_password"
PG_SSL="false"
JWT_SECRET="your_very_long_random_jwt_secret"
AUDIO_CDN_URL="https://racines-s3.id2real.net/audios"
AUDIO_CDN_DOMAIN="racines-s3.id2real.net"
⚠️ Values containing special characters (
#,=, spaces) must be in double quotes to be correctly interpreted.
Local development — .env.local
# PostgreSQL
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=racines
PG_USER=postgres
PG_PASSWORD=postgres
PG_SSL=false
# MinIO
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_USE_SSL=false
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET=audios
MINIO_PUBLIC_URL=http://localhost:9000
# Auth
JWT_SECRET=dev_secret_not_for_production
# Audio CDN (in dev, uses the fallback proxy)
AUDIO_CDN_URL=
AUDIO_PROXY_DISABLED=false
# PWA (disabled in dev by default)
NEXT_PUBLIC_PWA_ENABLED=false
Complete variable reference
PostgreSQL group
| Variable | Required | Default | Description | Impact if missing |
|---|---|---|---|---|
PG_HOST |
✅ | — | PostgreSQL server hostname | Connection impossible → app crash |
PG_PORT |
✅ | 5432 |
PostgreSQL port | Connection impossible |
PG_DATABASE |
✅ | racines |
Database name | Connection impossible |
PG_USER |
✅ | — | PostgreSQL user | Connection impossible |
PG_PASSWORD |
✅ | — | PostgreSQL password | Connection impossible |
PG_SSL |
❌ | false |
Enable SSL (true/false) |
Unencrypted connection if false |
Pool configuration (not configurable via env, hardcoded in src/lib/postgres.ts):
- Max connections: 20
- Idle timeout: 30s
- Connection timeout: 10s
MinIO group
| Variable | Required | Default | Description | Impact if missing |
|---|---|---|---|---|
MINIO_ENDPOINT |
✅ | — | MinIO server hostname | Audio upload impossible |
MINIO_PORT |
❌ | 9000 |
MinIO API port | — |
MINIO_USE_SSL |
❌ | false |
HTTPS for MinIO API | Unencrypted connection |
MINIO_ACCESS_KEY |
✅ | — | MinIO access key | Upload impossible |
MINIO_SECRET_KEY |
✅ | — | MinIO secret key | Upload impossible |
MINIO_BUCKET |
✅ | audios |
Storage bucket name | Upload to wrong bucket |
MINIO_PUBLIC_URL |
✅ | — | MinIO public URL (for audio URLs in dev) | Invalid audio URLs |
Audio / CDN group
🔴 Critical variables — read carefully
| Variable | Required | Default | Description |
|---|---|---|---|
AUDIO_CDN_URL |
Yes in production | — | Full URL of the MinIO audio CDN |
AUDIO_PROXY_DISABLED |
❌ | false |
Disable the Next.js fallback proxy |
AUDIO_CDN_DOMAIN |
❌ (auto-derived) | — | Hostname extracted from AUDIO_CDN_URL |
AUDIO_CDN_URL — critical details:
- Read by:
RootLayout(Server Component,force-dynamic) on every SSR request - Injected into:
window.__RACINES_CDN__as the first<script>in<head>, before any client chunk - Read by the client:
src/lib/audio-url.ts→getAudioUrl() - Impact if empty:
getAudioUrl()returns''→ audio URLs are empty → spurious requests to the current page → all audio is silent - The Docker entrypoint (
docker/entrypoint.sh) refuses to start if this variable is empty
# Production example
AUDIO_CDN_URL=https://racines-s3.id2real.net/audios
# Development example (uses the proxy)
AUDIO_CDN_URL= # empty → proxy automatically enabled
AUDIO_PROXY_DISABLED:
| Value | Behavior |
|---|---|
false (default) |
If AUDIO_CDN_URL is empty → proxy /api/audio/serve/ is active |
true |
Proxy disabled — AUDIO_CDN_URL must be set |
⚠️
AUDIO_PROXY_DISABLED=true+AUDIO_CDN_URL=(empty) = silent bug — all audio is silent without any visible error.
AUDIO_CDN_DOMAIN:
- Hostname extracted from AUDIO_CDN_URL (e.g. racines-s3.id2real.net)
- Used in the Content Security Policy (media-src, connect-src)
- If absent, entrypoint.sh derives it automatically from AUDIO_CDN_URL
- Can be explicitly overridden if the CDN domain differs from the MinIO domain
Authentication group
| Variable | Required | Description | Impact if missing |
|---|---|---|---|
JWT_SECRET |
✅ | Secret key to sign admin JWTs (HS256) | Invalid tokens → all admins logged out |
Recommendations:
- Minimum 32 random characters
- Generate with: openssl rand -base64 32
- Changing it invalidates all active sessions (re-login required)
Email group (optional)
These variables are needed if you want the contact form to send email notifications.
| Variable | Required | Description |
|---|---|---|
SMTP_HOST |
❌ | SMTP server hostname |
SMTP_PORT |
❌ | SMTP port (e.g. 587) |
SMTP_USER |
❌ | SMTP user |
SMTP_PASSWORD |
❌ | SMTP password |
SMTP_FROM |
❌ | Sender email address (e.g. noreply@racines.app) |
If these variables are absent, the contact form saves messages to the database but does not send notification emails.
NEXT_PUBLIC_* variables (build-time)
These variables are embedded in the JavaScript bundle at build time. They cannot be changed after a build without rebuilding.
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_PWA_ENABLED |
true (in prod) |
Enables the PWA manifest and Apple metadata. Set to false in dev to avoid SW conflicts. |
GitLab CI/CD variables (secrets)
These variables are configured in GitLab → Settings → CI/CD → Variables. They are never committed to the repository.
| Variable | Description |
|---|---|
DEPLOY_HOST |
Production server hostname |
DEPLOY_USER |
SSH deployment user |
DEPLOY_KEY |
SSH private key for deployment |
REGISTRY_URL |
GitLab Container Registry URL |
DOCKER_AUTH_CONFIG |
Docker Registry authentication config |
Quick check
# Check variables in the running container
docker exec racines-app env | grep -E "PG_|MINIO_|AUDIO_|JWT_"
# Verify that AUDIO_CDN_URL is properly set
docker exec racines-app sh -c 'echo $AUDIO_CDN_URL'
# Health check
curl http://localhost:3000/api/health/live