Environment Variable Reference
Bliss Finance uses a single root .env file as the source of truth for all services. Both the Next.js API layer and the Express backend service read from this shared file, ensuring configuration stays consistent across the stack.
How it works
- Docker Compose reads the root
.envautomatically — noenv_filedirective needed. scripts/setup.shgenerates cryptographic secrets (ENCRYPTION_SECRET,JWT_SECRET_CURRENT,NEXTAUTH_SECRET,INTERNAL_API_KEY) so you never have to create them by hand. Run it once after copying.env.exampleto.env.- Optional integrations (Plaid, Gemini AI, Twelve Data, Sentry) are activated simply by adding the relevant API keys. The application degrades gracefully when they are absent.
- Test-specific overrides: each service may have a
.env.testfile that overridesDATABASE_URLto point at an isolated test database. These files are loaded automatically by the test runners and should never be committed.
Minimal Docker Setup
For a basic Docker deployment, scripts/setup.sh generates all required secrets automatically (ENCRYPTION_SECRET, JWT_SECRET_CURRENT, NEXTAUTH_SECRET, INTERNAL_API_KEY). It also sets safe defaults for DATABASE_URL, REDIS_URL, and all service URLs. You do not need to configure anything to get a working local instance.
The only variables you might want to customize are the optional integration keys:
| Integration | Variables | Purpose |
|---|---|---|
| Plaid | PLAID_CLIENT_ID, PLAID_SECRET | Bank account linking |
| Gemini AI | GEMINI_API_KEY | AI classification and insights |
| Market data | TWELVE_DATA_API_KEY | Stock price fetching |
| Currency rates | CURRENCYLAYER_API_KEY | Automatic FX rate fetching |
| Observability | SENTRY_DSN | Error tracking |
All of these are optional. The application works without them and degrades gracefully.
Database
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | Yes | postgresql://bliss:changeme@localhost:5432/bliss | PostgreSQL connection string used by Prisma in both services. Inside Docker the host is postgres instead of localhost. |
POSTGRES_PASSWORD | Yes | changeme | Superuser password passed to the postgres Docker image to bootstrap the database. |
Redis
| Variable | Required | Default | Description |
|---|---|---|---|
REDIS_URL | Yes | redis://:changeme@localhost:6379 | Full Redis connection URL (include password if set). Used by BullMQ queues and workers. |
REDIS_PASSWORD | Yes | changeme | Password for the redis Docker service. Must match the password embedded in REDIS_URL. |
REDIS_SKIP_TLS_CHECK | No | false | Set to true when Redis uses TLS with a self-signed certificate. For managed services like Upstash, leave as false. |
Secrets
All four required secrets in this section are generated by scripts/setup.sh.
| Variable | Required | Default | Description |
|---|---|---|---|
ENCRYPTION_SECRET | Yes | — | AES-256-GCM key used to encrypt PII fields (transaction descriptions, account numbers, Plaid access tokens). Minimum 32 characters. |
ENCRYPTION_SECRET_PREVIOUS | No | — | Set during encryption key rotation. The application will try the previous key when decryption with the current key fails. Remove once migration is complete. |
JWT_SECRET_CURRENT | Yes | — | HMAC secret used to sign and verify JWT access tokens. |
JWT_SECRET_PREVIOUS | No | — | Set during JWT secret rotation. Tokens signed with the previous secret remain valid until they expire. |
NEXTAUTH_SECRET | Yes | — | Secret used by NextAuth.js for session cookie signing. |
INTERNAL_API_KEY | Yes | — | Shared secret for server-to-server calls between the API layer and the backend service. Must be identical in both services. |
API Layer (Next.js)
| Variable | Required | Default | Description |
|---|---|---|---|
NEXTAUTH_URL | Yes | http://localhost:3000 | Full public URL of the Next.js API layer. Used by NextAuth for callback URLs. |
BACKEND_URL | Yes | http://localhost:3001 | Internal URL of the Express backend service. Used for server-to-server event dispatch and proxy routes. Not exposed to the browser. |
COOKIE_DOMAIN | No | — | Cookie domain for cross-subdomain auth (e.g., .bliss.finance). Leave empty for localhost development. |
Backend Service (Express)
| Variable | Required | Default | Description |
|---|---|---|---|
PORT | No | 3001 | Port the Express backend listens on. |
ALLOWED_ORIGINS | No | http://localhost:3000 | Comma-separated list of allowed CORS origins for the backend. |
Storage
File upload storage is pluggable. The default is local disk; switch to Google Cloud Storage by setting STORAGE_BACKEND=gcs and providing the GCS variables.
| Variable | Required | Default | Description |
|---|---|---|---|
STORAGE_BACKEND | No | local | local for filesystem storage, gcs for Google Cloud Storage. |
LOCAL_STORAGE_DIR | No | ./data/uploads | Directory for uploaded files when using local storage. |
GCS_BUCKET_NAME | No | — | GCS bucket name. Required when STORAGE_BACKEND=gcs. |
GCS_SERVICE_ACCOUNT_JSON | No | — | GCS service account credentials as a JSON string. Required when STORAGE_BACKEND=gcs. |
Frontend
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_API_URL | Yes | http://localhost:3000 | Public URL of the API layer, baked into the web bundle at build time. Changing it requires a rebuild. |
FRONTEND_URL | Yes | http://localhost:8080 | Public URL of the frontend app. Used by the API layer for CORS whitelisting. |
Plaid (optional)
Plaid integration is optional. CSV import works without it. To enable bank-account linking, provide a Plaid client ID and secret.
| Variable | Required | Default | Description |
|---|---|---|---|
PLAID_CLIENT_ID | No | — | Plaid API client ID. |
PLAID_SECRET | No | — | Plaid API secret. |
PLAID_ENV | No | sandbox | Plaid environment: sandbox, development, or production. |
PLAID_WEBHOOK_URL | No | — | Public URL for Plaid webhook delivery. Required in production to receive transaction updates. |
PLAID_HISTORY_DAYS | No | 1 | Default number of days of transaction history fetched on initial Plaid link. Written to Tenant.plaidHistoryDays at signup. |
AI (optional)
AI features (vector similarity classification, Gemini-powered categorization) are disabled when the API key is absent.
| Variable | Required | Default | Description |
|---|---|---|---|
GEMINI_API_KEY | No | — | Google Gemini API key. Enables the vector classification tier and AI-powered transaction categorization. |
Market Data (optional)
Stock price fetching is provided by Twelve Data and is disabled when the API key is not set.
| Variable | Required | Default | Description |
|---|---|---|---|
TWELVE_DATA_API_KEY | No | — | API key for Twelve Data. Enables real-time and historical pricing for stocks, ETFs, and funds (10,000+ symbols across 27+ markets). |
Currency Rates (optional)
Automatic historical exchange rate fetching is disabled when the API key is not set. Rates can still be entered manually via the UI.
| Variable | Required | Default | Description |
|---|---|---|---|
CURRENCYLAYER_API_KEY | No | — | API key for CurrencyLayer . Used by portfolio processing and analytics to fetch historical FX rates. |
Observability (optional)
Error tracking and performance monitoring via Sentry. Leave all three unset to disable.
| Variable | Required | Default | Description |
|---|---|---|---|
SENTRY_DSN | No | — | Sentry Data Source Name. Enables error reporting when set. |
SENTRY_ORG | No | — | Sentry organization slug. Used for source-map uploads during CI builds. |
SENTRY_PROJECT | No | — | Sentry project slug. Used alongside SENTRY_ORG for source-map uploads. |