Environment Variables
Every environment variable Nextly reads, organized by category with required vs. optional indicators.
Nextly reads environment variables for database connections, authentication, storage, email, and other runtime settings. Most live in the central env schema (packages/nextly/src/shared/lib/env.ts); storage adapter env vars are per-adapter and read by the adapter packages directly.
Copy .env.example to .env and fill in values:
cp .env.example .envCanonical .env.example
The base template templates/base/.env.example ships the minimum required variables:
# Nextly Configuration
# Generated by create-nextly-app
# Database Configuration
DB_DIALECT=postgresql
DATABASE_URL=postgresql://user:password@localhost:5432/nextly_dev
# Authentication (REQUIRED)
# Generate with: openssl rand -base64 32
NEXTLY_SECRET=change-me-generate-a-secure-secret
# Application URL
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Storage (per-adapter — see "Storage" section below)The create-nextly-app scaffolder fills in DB_DIALECT, DATABASE_URL, and an auto-generated 32-byte base64 NEXTLY_SECRET for you. For a production deployment, regenerate NEXTLY_SECRET with:
openssl rand -base64 32Database
Source: packages/nextly/src/shared/lib/env.ts.
| Variable | Required | Default | Description |
|---|---|---|---|
DB_DIALECT | Yes | postgresql | Database dialect: postgresql, mysql, or sqlite. |
DATABASE_URL | Yes (PostgreSQL/MySQL) | — | Full database connection URL. Required for postgresql and mysql; optional for sqlite (paired with SQLITE_PATH). Validated as a URL. |
SQLITE_PATH | Optional (SQLite only) | file:./data/nextly.db (factory default) | SQLite file path; alternative to DATABASE_URL for the sqlite dialect. |
DB_POOL_MAX | No | 20 | Max connections in the pool. Min: 1. |
DB_POOL_MIN | No | 2 | Min connections in the pool. Min: 0. |
DB_POOL_IDLE_TIMEOUT | No | 30000 | Idle connection timeout in milliseconds. Min: 1000. |
DB_QUERY_TIMEOUT | No | 15000 | Query timeout in milliseconds. Min: 1000. |
DB_HEALTHCHECK_INTERVAL_MS | No | 30000 | Health-check interval in milliseconds. Min: 1000. |
DB_SNAKE_CASE | No | false | Use snake_case for database column names instead of camelCase. |
Connection-string formats
# PostgreSQL (recommended for production)
DATABASE_URL=postgresql://user:password@localhost:5432/nextly_dev
# MySQL
DATABASE_URL=mysql://root:root@localhost:3306/nextly_dev
# SQLite (development / single-instance only)
DATABASE_URL=file:./dev.db
# or
SQLITE_PATH=./dev.dbRuntime
| Variable | Required | Default | Description |
|---|---|---|---|
NODE_ENV | No | development | Runtime environment: development, production, or test. Affects production-only checks below. |
Authentication
Nextly uses a custom JWT auth system (access + refresh tokens, sessions, API keys, RBAC). There is no OAuth.
| Variable | Required | Default | Description |
|---|---|---|---|
NEXTLY_SECRET | Yes (production: ≥ 32 chars) | — | Secret used to sign JWTs and other crypto. Production startup throws if it is missing or shorter than 32 characters. Generate with openssl rand -base64 32. |
NEXTLY_ALLOWED_ORIGINS | No | — | Comma-separated list of additional origins allowed for CSRF validation (e.g. https://admin.example.com,https://staging.example.com). The app's own origin is always allowed. |
Application URLs
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_APP_URL | Yes (production) | — | Public-facing app URL. Used in client-side code and as the fallback for email-link baseUrl. Production startup throws if missing. |
API_BASE_URL | No | http://localhost:3000/api | Base URL for API routes. Validated as a URL. |
Storage (per-adapter)
The default storage backend is local disk under ./public/uploads/. No env vars are needed for default storage.
Cloud adapters are opt-in. The variables below are read by the adapter packages, not by the central env schema, so they only need to exist when you actually configure that adapter in nextly.config.ts. Nothing else (env-validation, etc.) checks for them.
S3 / S3-compatible — @nextlyhq/storage-s3
Works with AWS S3, Cloudflare R2, MinIO, and DigitalOcean Spaces. The plugin accepts these values directly; the env-var names below are the conventional ones used in our examples (and what your nextly.config.ts typically references with process.env.X).
| Variable | Required | Description |
|---|---|---|
S3_BUCKET | Yes | Bucket name. |
AWS_REGION | Yes | AWS region (e.g. us-east-1). Use auto for Cloudflare R2. |
AWS_ACCESS_KEY_ID | Yes | Access key ID. |
AWS_SECRET_ACCESS_KEY | Yes | Secret access key. |
S3_ENDPOINT | Sometimes | Custom endpoint URL. Required for R2 and MinIO. |
S3_PUBLIC_URL | No | Public URL prefix (e.g. https://pub-xxxx.r2.dev for R2 or a CDN domain). |
S3_FORCE_PATH_STYLE | No | Set true for MinIO and other path-style providers. |
import { s3Storage } from "@nextlyhq/storage-s3";
storage: [
s3Storage({
bucket: process.env.S3_BUCKET!,
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
endpoint: process.env.S3_ENDPOINT,
forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true",
publicUrl: process.env.S3_PUBLIC_URL,
collections: { media: true },
}),
];Vercel Blob — @nextlyhq/storage-vercel-blob
Recommended for Vercel deployments.
| Variable | Required | Description |
|---|---|---|
BLOB_READ_WRITE_TOKEN | Yes | Vercel Blob token from the Vercel dashboard. The adapter reads this directly when the token config option is omitted. |
UploadThing — @nextlyhq/storage-uploadthing
| Variable | Required | Description |
|---|---|---|
UPLOADTHING_TOKEN | Yes | UploadThing API token. The adapter reads this directly when the token config option is omitted. |
Email / SMTP
Source: packages/nextly/src/shared/lib/env.ts. Required only if you send emails (password resets, notifications). In production, if any SMTP variable is set, all four of SMTP_HOST, SMTP_USER, SMTP_PASS, SMTP_FROM must be set or the env validator throws.
| Variable | Required | Default | Description |
|---|---|---|---|
SMTP_HOST | No | — | SMTP server hostname (e.g. smtp.gmail.com). |
SMTP_PORT | No | 587 | SMTP port. 587 for TLS, 465 for SSL. Range: 1–65535. |
SMTP_USER | No | — | SMTP authentication username. |
SMTP_PASS | No | — | SMTP authentication password. |
SMTP_FROM | No | — | From address for outgoing emails. Validated as an email. |
For local development, the repo ships a Mailpit profile (docker compose --profile with-mailpit up -d mailpit) on host ports 1025 (SMTP) and 8025 (web UI) — see Email guide for details.
Security
These env vars are read by middleware and security helpers. None are part of the central env schema; they are read directly by the modules that use them.
| Variable | Required | Default | Description | Read by |
|---|---|---|---|---|
TRUSTED_PROXY_IPS | No | empty | Comma-separated CIDR list of trusted reverse-proxy IPs. Combined with security.trustProxy: true, controls which X-Forwarded-For values are honoured for client-IP resolution (rate limiting, refresh-token binding, audit logging). | packages/nextly/src/utils/get-trusted-client-ip.ts |
Performance — permission cache
Nextly's RBAC layer ships a hybrid (in-memory LRU + database) permission cache. These env vars tune it; none are part of the central env schema — they are read directly by the permission service.
| Variable | Required | Default | Description | Read by |
|---|---|---|---|---|
PERMISSION_CACHE_ENABLED | No | true | Set to false or 0 to disable the hybrid permission cache. | packages/nextly/src/services/lib/permissions.ts |
PERMISSION_CACHE_TTL_SECONDS | No | 86400 | Time-to-live for database cache entries (seconds). | packages/nextly/src/services/lib/permissions.ts |
PERMISSION_CACHE_MEMORY_SIZE | No | 10000 | In-memory LRU cache size (number of entries). | packages/nextly/src/services/lib/permissions.ts |
The database permission cache benefits from periodic cleanup. A typical daily cron:
0 2 * * * curl -X POST http://localhost:3000/api/auth/cache/cleanupDebug
| Variable | Required | Default | Description | Read by |
|---|---|---|---|---|
DEBUG_RBAC | No | — | Set 1 to log detailed RBAC permission decisions. | packages/nextly/src/services/lib/permissions.ts |
DEBUG_CACHE | No | — | Set 1 to log permission-cache hit/miss/eviction details. | packages/nextly/src/domains/auth/services/permission-cache-service.ts |
Docker development (optional)
Used by the bundled docker-compose.yml for local Postgres / Redis / Adminer / Drizzle Studio / Mailpit setup. Not needed when connecting to an existing database.
| Variable | Default | Description |
|---|---|---|
DB_NAME | nextly_dev | PostgreSQL database name. |
DB_USER | postgres | PostgreSQL user. |
DB_PASSWORD | — | PostgreSQL password. Override in production. |
DB_PORT | 5432 | PostgreSQL host port. |
ADMINER_PORT | 8080 | Adminer (database browser) UI port. |
REDIS_PORT | 6379 | Redis cache port. |
DRIZZLE_STUDIO_PORT | 4983 | Drizzle Studio port for the database GUI. |
Example .env files
Minimal production
# Runtime
NODE_ENV=production
# Database
DB_DIALECT=postgresql
DATABASE_URL=postgresql://user:password@db.example.com:5432/nextly_prod
# Auth
NEXTLY_SECRET=your-generated-secret-at-least-32-characters-long
NEXT_PUBLIC_APP_URL=https://your-domain.com
# Storage (Vercel Blob example)
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_xxxxxxxxxxxxDevelopment with S3-compatible storage (MinIO)
# Database
DB_DIALECT=postgresql
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/nextly_dev
# Auth
NEXTLY_SECRET=dev-secret-minimum-32-characters-long-replace-in-production
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Storage (MinIO)
S3_BUCKET=nextly-dev
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
S3_ENDPOINT=http://localhost:9000
S3_FORCE_PATH_STYLE=trueNext steps
- Nextly config — configure storage and security from
nextly.config.ts - Database — choose and configure PostgreSQL, MySQL, or SQLite
- Authentication guide — auth-related env vars in depth
- Deployment guide — production environment-variable checklist