The API reads its configuration from api/.env. The template is located at api/.env.template.Variables marked as secret (such as APP_SECRET, EMAIL_API_KEY, TWILIO_AUTH_TOKEN, CLOUDINARY_SECRET, API_PASS_KEY, and S3/Google credentials) must never be committed to source control. Store them securely using your environment’s secrets management solution.
Database
| Variable | Description | Default | Required |
|---|
DATABASE_URL | PostgreSQL connection URL | postgres://<username>@localhost:5432/bloom_prisma | Yes |
Server
| Variable | Description | Default | Required |
|---|
PORT | Port the API server listens on | 3100 | Yes |
NODE_ENV | Runtime environment (development, production, test) | development | Yes |
CORS_ORIGINS | JSON array of exact-match URLs allowed to make cross-origin requests | ["http://localhost:3000", "http://localhost:3001"] | Yes |
CORS_REGEX | JSON array of strings converted to regex patterns for additional CORS allowances | ["test1", "test2"] | No |
PROXY_URL | URL for the proxy server | — | No |
Authentication
APP_SECRET and API_PASS_KEY are secrets. Use long, randomly generated values in production.
| Variable | Description | Default | Required |
|---|
APP_SECRET | Secret key used to sign JWTs and session tokens | some-long-secret-key | Yes |
MFA_CODE_LENGTH | Number of digits in a generated MFA code | 5 | Yes |
MFA_CODE_VALID | Time-to-live for MFA codes, in milliseconds | 60000 (1 minute) | Yes |
AUTH_LOCK_LOGIN_COOLDOWN | Duration of an account lock after too many failed login attempts, in milliseconds | 1800000 (30 minutes) | Yes |
AUTH_LOCK_LOGIN_AFTER_FAILED_ATTEMPTS | Number of failed login attempts before an account is locked | 5 | Yes |
API_PASS_KEY | Passkey required on all incoming API requests. The frontend services must send the same key | some-key-here | Yes |
Email
EMAIL_API_KEY is a secret SendGrid API key. Keep it out of source control.
| Variable | Description | Default | Required |
|---|
EMAIL_API_KEY | SendGrid API key used to send transactional emails | SG.ExampleApiKey | Yes |
SMS
TWILIO_AUTH_TOKEN is a secret. Store it securely.
| Variable | Description | Default | Required |
|---|
TWILIO_PHONE_NUMBER | Twilio phone number used to send SMS messages | — | No |
TWILIO_ACCOUNT_SID | Twilio account SID | — | No |
TWILIO_AUTH_TOKEN | Twilio account auth token | — | No |
File storage
CLOUDINARY_SECRET, S3_ACCESS_TOKEN, and S3_SECRET_TOKEN are secrets.
| Variable | Description | Default | Required |
|---|
CLOUDINARY_SECRET | Cloudinary API secret for image management | — | No |
CLOUDINARY_CLOUD_NAME | Cloudinary cloud name | exygy | No |
S3_REGION | AWS region for the S3 bucket used for large file transfers (CSV/spreadsheet zips) | — | No |
S3_BUCKET | S3 bucket name for large file transfers | — | No |
S3_ACCESS_TOKEN | AWS access key ID for the S3 service account | — | No |
S3_SECRET_TOKEN | AWS secret access key for the S3 service account | — | No |
Translation
| Variable | Description | Default | Required |
|---|
GOOGLE_API_EMAIL | Google Translate service account email | — | No |
GOOGLE_API_ID | Google Translate API project ID | — | No |
GOOGLE_API_KEY | Google Translate API key | — | No |
Cron jobs
All cron schedule strings use standard cron syntax (minute hour day month weekday).| Variable | Description | Default |
|---|
LISTING_PROCESSING_CRON_STRING | Schedule for the listing processing cron job | 0 * * * * (every hour) |
LOTTERY_PUBLISH_PROCESSING_CRON_STRING | Schedule for the lottery publish cron job | 58 23 * * * (23:58 daily) |
LOTTERY_PROCESSING_CRON_STRING | Schedule for the lottery cron job | 0 * * * * (every hour) |
MSQ_RETIRE_CRON_STRING | Schedule for the MSQ retire cron job (should run after LISTING_PROCESSING_CRON_STRING) | 5 * * * * |
PII_DELETION_CRON_STRING | Schedule for the PII deletion cron job | 0 * * * * |
USER_DELETION_CRON_STRING | Schedule for the user deletion cron job | 0 * * * * |
USER_DELETION_WARN_CRON_STRING | Schedule for the user deletion warning cron job | 0 * * * * |
DUPLICATES_PROCESSING_CRON_STRING | Schedule for the duplicate application (AFS) detection cron job | 15 * * * * |
TEMP_FILE_CLEAR_CRON_STRING | Schedule for the temporary file clearing cron job | 0 * * * |
Rate limiting
| Variable | Description | Default | Required |
|---|
THROTTLE_TTL | Duration of the rate limiting window, in milliseconds | 3600000 (1 hour) | Yes |
THROTTLE_LIMIT | Maximum number of requests allowed per window | 100 | Yes |
Lottery
| Variable | Description | Default | Required |
|---|
LOTTERY_DAYS_TILL_EXPIRY | Number of days before lottery data expires and is purged | 45 | No |
Data expiry
| Variable | Description | Default | Required |
|---|
APPLICATION_DAYS_TILL_EXPIRY | Number of days before application PII data is deleted | — | No |
USERS_DAYS_TILL_EXPIRY | Number of days of inactivity before a user account is deleted | — | No |
Geocoding and reCAPTCHA
| Variable | Description | Default | Required |
|---|
RECAPTCHA_KEY | Google reCAPTCHA v3 API key. When set, reCAPTCHA validation is enabled on the backend | — | No |
GOOGLE_CLOUD_PROJECT_ID | Google Cloud project ID required for reCAPTCHA setup | — | No |
RECAPTCHA_THRESHOLD | Minimum reCAPTCHA score (0–1) required to bypass two-factor authentication | 0.7 | No |
ENABLE_RECAPTCHA | When TRUE, reCAPTCHA scores can block login flows | TRUE | No |
Other
| Variable | Description | Default | Required |
|---|
TIME_ZONE | Default time zone for dates in data exports | America/Los_Angeles | Yes |
PARTNERS_PORTAL_URL | URL of the Partners Portal frontend, used in email links | http://localhost:3001 | Yes |
SKIP_SNAPSHOTS | When TRUE, creating application snapshots is skipped | FALSE | No |
CONTACT_EMAIL | Support contact email address displayed in the UI and emails | [email protected] | No |
DB_NO_SSL | When TRUE, the database connection is made without SSL. Use only for local development or CI | TRUE | No |
TEST_CONNECTION_STRING | Connection string used by the script runner data transfer job during testing | — | No |
The Public Site reads its configuration from sites/public/.env. The template is located at sites/public/.env.template.Any changes to this file must be reflected in all deployed environments, including CI.
API_PASS_KEY must match the value set in the API. Keep it out of source control.
Backend connection
| Variable | Description | Default | Required |
|---|
BACKEND_API_BASE | Base URL for direct API requests | http://127.0.0.1:3100 | Yes |
BACKEND_API_BASE_NEW | Base URL for Next.js API route proxied requests | http://127.0.0.1:3100 | Yes |
BACKEND_PROXY_BASE | Base URL for the backend proxy, if used | — | No |
LISTINGS_QUERY | API path for the listings endpoint | /listings | Yes |
API_PASS_KEY | Passkey sent with all API requests. Must match API_PASS_KEY in the API | some-key-here | Yes |
Server
| Variable | Description | Default | Required |
|---|
NEXTJS_PORT | Port the Next.js server listens on | 3000 | Yes |
IDLE_TIMEOUT | Number of minutes before an idle session is logged out | 5 | Yes |
Jurisdiction
| Variable | Description | Default | Required |
|---|
JURISDICTION_NAME | Name of the jurisdiction displayed in the UI | Bloomington | Yes |
LANGUAGES | Comma-separated list of supported language codes | en,es,zh,vi,tl,bn,ar,ko,hy,fa | Yes |
Integrations
| Variable | Description | Default | Required |
|---|
CLOUDINARY_CLOUD_NAME | Cloudinary cloud name for image delivery | exygy | Yes |
MAPBOX_TOKEN | Mapbox API token for map display | — | No |
GA_KEY | Google Analytics measurement ID | G-2WQMFT5BES | No |
GTM_KEY | Google Tag Manager container ID | GTM-KF22FJP | No |
NEW_RELIC_APP_NAME | New Relic application name | Bloom Public | No |
NEW_RELIC_LICENSE_KEY | New Relic license key | — | No |
SENTRY_ORG | Sentry organization slug for error tracking | — | No |
RECAPTCHA_KEY | Google reCAPTCHA site key for client-side validation | — | No |
HOUSING_COUNSELOR_SERVICE_URL | Path or URL for the housing counselor service | /get-assistance | No |
SEO and maintenance
| Variable | Description | Default | Required |
|---|
ALLOW_SEO_INDEXING | Set to TRUE only in production to enable search engine indexing. Non-production deployments should use FALSE to serve noindex | FALSE | Yes |
MAINTENANCE_WINDOW | Comma-separated start and end timestamps (YYYY-MM-DD HH:mm Z) for a scheduled maintenance window | — | No |
SITE_MESSAGE_WINDOW | Comma-separated start and end timestamps for a site-wide message banner | — | No |
Feature toggles
| Variable | Description | Default | Required |
|---|
SHOW_PUBLIC_LOTTERY | When TRUE, lottery-related UI is shown on the public site | TRUE | No |
SHOW_MANDATED_ACCOUNTS | When TRUE, mandated account creation flows are enabled | FALSE | No |
SHOW_PWDLESS | When TRUE, passwordless (single-use code) login is enabled | FALSE | No |
SHOW_NEW_SEEDS_DESIGNS | When TRUE, new Seeds design system components are used | FALSE | No |
| Variable | Description | Default | Required |
|---|
MAX_BROWSE_LISTINGS | Maximum number of closed listings shown in the closed listings list | 10 | No |
CACHE_REVALIDATE | Duration in seconds for Next.js ISR cache revalidation on listing detail pages | 30 | No |
Accessibility testing
| Variable | Description | Default | Required |
|---|
AXE_DEVELOPER_HUB_API_KEY | API key for Axe DevTools Hub accessibility testing | — | No |
RUN_ACCESSIBILITY_E2E_TESTS | When TRUE, accessibility end-to-end tests are included in the test run | FALSE | No |
The Partners Site reads its configuration from sites/partners/.env. The template is located at sites/partners/.env.template.Any changes to this file must be reflected in all deployed environments, including CI.
API_PASS_KEY and CLOUDINARY_KEY are secrets. Keep them out of source control.
Backend connection
| Variable | Description | Default | Required |
|---|
BACKEND_API_BASE | Base URL for API requests | http://localhost:3100 | Yes |
BACKEND_PROXY_BASE | Base URL for the backend proxy, if used | — | No |
LISTINGS_QUERY | API path for the listings endpoint | /listings | Yes |
API_PASS_KEY | Passkey sent with all API requests. Must match API_PASS_KEY in the API | some-key-here | Yes |
Server
| Variable | Description | Default | Required |
|---|
NEXTJS_PORT | Port the Next.js server listens on | 3001 | Yes |
Integrations
| Variable | Description | Default | Required |
|---|
CLOUDINARY_CLOUD_NAME | Cloudinary cloud name for image delivery | exygy | Yes |
CLOUDINARY_KEY | Cloudinary API key for signed uploads | abcxyz | Yes |
CLOUDINARY_SIGNED_PRESET | Cloudinary signed upload preset | test123 | Yes |
MAPBOX_TOKEN | Mapbox API token for map display | — | No |
RECAPTCHA_KEY | Google reCAPTCHA site key for client-side validation | — | No |
Authentication
| Variable | Description | Default | Required |
|---|
SHOW_SMS_MFA | When TRUE, SMS-based multi-factor authentication is enabled as a login option | TRUE | No |
SEO
| Variable | Description | Default | Required |
|---|
ALLOW_SEO_INDEXING | Set to TRUE only in production to enable search engine indexing | FALSE | Yes |
Feature toggles
| Variable | Description | Default | Required |
|---|
SHOW_LOTTERY | When TRUE, lottery management features are visible in the Partners Portal | FALSE | No |
APPLICATION_EXPORT_AS_SPREADSHEET | When TRUE, application exports are produced as spreadsheets. When FALSE, exports use CSV format | FALSE | No |
LIMIT_CLOSED_LISTING_ACTIONS | When TRUE, edit, republish, and reopen actions are restricted on closed listings | FALSE | No |
LOTTERY_DAYS_TILL_EXPIRY | Number of days before lottery data expires. Should match the API value | 45 | No |
File downloads
| Variable | Description | Default | Required |
|---|
USE_SECURE_DOWNLOAD_PATHWAY | When TRUE, exported listings and applications are downloaded through a private S3 bucket pathway | TRUE | No |
Accessibility testing
| Variable | Description | Default | Required |
|---|
AXE_DEVELOPER_HUB_API_KEY | API key for Axe DevTools Hub accessibility testing | — | No |
RUN_ACCESSIBILITY_E2E_TESTS | When TRUE, accessibility end-to-end tests are included in the test run | — | No |