Configuration reference
Every environment variable NextCRM reads, grouped by area, with what it does and whether you need it.
NextCRM is configured with environment variables. This page lists the variables the code actually reads; the example files in the repository (.env.docker, .env.example, .env.local.example) use the same names.
"Required" means the app or a core flow (login, file storage) breaks without it. Optional variables switch on one feature.
With Docker Compose, a variable only reaches the app if it is listed under services.app.environment. Both compose files list every variable on this page except the build-time and "Other" ones. See Which variables reach the app.
Database
| Variable | Required | What it does |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string used by the app, Prisma migrations and the seed. The database needs the pgvector extension. |
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB | Docker only | Credentials of the bundled postgres service. The compose files build DATABASE_URL and the DB_* values from them. Defaults: nextcrm / changeme / nextcrm. |
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME | Docker only | Read by docker-entrypoint.sh to wait for Postgres and to check whether the database needs seeding. Set by the compose files. |
Authentication
| Variable | Required | What it does |
|---|---|---|
BETTER_AUTH_SECRET | Yes | Signs sessions. Generate with openssl rand -base64 32. Changing it logs everyone out. In Docker, if it is empty, the entrypoint generates one on the first start and keeps it in the app_data volume. |
BETTER_AUTH_URL | Yes | Public base URL of the instance, for example https://crm.example.com. Used by BetterAuth for callbacks. The compose files set it from APP_URL. |
GOOGLE_ID, GOOGLE_SECRET | No | OAuth client for "Sign in with Google". Redirect URI: <your URL>/api/auth/callback/google. |
Sessions last 7 days and are refreshed every 24 hours. Password login is disabled; users sign in with an email code or Google.
App URL and name
| Variable | Required | What it does |
|---|---|---|
APP_URL | Docker only | Public URL of the instance. The compose files pass it to the app as BETTER_AUTH_URL and NEXT_PUBLIC_APP_URL. Default http://localhost:3000. |
NEXT_PUBLIC_APP_URL | Yes | Public URL of the instance. Used for links in emails (including the unsubscribe link in campaign emails), the Google Calendar OAuth redirect URI and the Calendly webhook URL. Set it to the same value as BETTER_AUTH_URL. |
NEXT_PUBLIC_APP_NAME | Recommended | Product name shown in the UI and used as the sender name of system emails. |
NEXT_PUBLIC_APP_DOMAIN | No | Only used to build a fallback invoice sender (invoices@<domain>) when EMAIL_FROM is not set. |
Encryption
| Variable | Required | What it does |
|---|---|---|
EMAIL_ENCRYPTION_KEY | Yes | 64 hexadecimal characters (32 bytes). Generate with openssl rand -hex 32. In Docker, if it is empty, the entrypoint generates one on the first start and keeps it in the app_data volume. Encrypts, with AES-256-GCM: AI provider keys saved in the admin panel or profiles, users' mailbox credentials, Google Calendar tokens, Calendly settings and plugin secrets. |
Set EMAIL_ENCRYPTION_KEY once and keep it. With a different key, all stored encrypted values become unreadable. Back it up together with the database (in Docker: the app_data volume, unless you set it yourself).
File storage
NextCRM talks to any S3-compatible store through the AWS SDK with path-style URLs.
| Variable | Required | What it does |
|---|---|---|
MINIO_ENDPOINT | Yes | S3 endpoint URL the server connects to, for example http://minio:9000 inside Docker. https:// endpoints work. |
MINIO_PUBLIC_ENDPOINT | If different | URL browsers use to reach the store. Presigned upload and invoice download URLs are signed for this address, and file links are built as <MINIO_PUBLIC_ENDPOINT>/<bucket>/<key>. Read at runtime. Falls back to NEXT_PUBLIC_MINIO_ENDPOINT, then MINIO_ENDPOINT. |
NEXT_PUBLIC_MINIO_ENDPOINT | No | Older name for MINIO_PUBLIC_ENDPOINT, still honoured. |
MINIO_PUBLIC_URL | Docker only | Compose variable passed to the app as MINIO_PUBLIC_ENDPOINT. Default http://localhost:9000. |
MINIO_ACCESS_KEY, MINIO_SECRET_KEY | Yes | S3 credentials. |
MINIO_BUCKET | Yes | Bucket name. The Docker entrypoint creates it if missing. |
MINIO_ROOT_USER, MINIO_ROOT_PASSWORD | Docker only | Credentials of the bundled minio service; the compose files pass them to the app as access and secret key. |
The app throws at startup if any of the four required MINIO_* values is missing.
File links are plain URLs, so browsers need anonymous read access to the upload folders (avatars/, images/, documents/, uploads/, thumbnails/). The Docker entrypoint sets that bucket policy when the bucket has none. Invoices (invoices/) stay private and are served through presigned links.
| Variable | Required | What it does |
|---|---|---|
RESEND_API_KEY | For login | Resend API key. Sends login codes, invitations, invoice emails, campaigns and scheduled reports. Takes priority over a key saved under Administration → Services; leave it empty to use that key. |
EMAIL_FROM | For login | Sender address for login codes, invitations, invoice emails and SMTP notifications. Must be a sender verified in Resend. |
RESEND_FROM_EMAIL | For campaigns | Sender for campaign emails, scheduled reports and automation notifications. |
RESEND_WEBHOOK_SECRET | No | Secret used to verify calls to /api/campaigns/webhooks/resend (delivery events for campaigns). |
EMAIL_HOST, EMAIL_USERNAME, EMAIL_PASSWORD | No | SMTP server for system notifications. The app connects on port 465 with TLS. |
MAIL_ALLOW_PRIVATE_HOSTS | No | true lets users connect mailboxes (IMAP/SMTP) on private or internal IP addresses. Off by default to block server-side request forgery. |
Details: Email.
AI providers
Each key can also be set in Administration → LLM Keys or by users in their profile. The environment variable wins when set; empty values and template placeholders such as sk-placeholder-… or your-openai-api-key count as not set. See AI provider keys.
| Variable | Required | What it does |
|---|---|---|
OPENAI_API_KEY | No | Embeddings for semantic search and "Find similar", document enrichment, AI template generation, contact and target enrichment. Embedding and document jobs read only this variable, not the admin-panel key. |
ANTHROPIC_API_KEY | No | Background target enrichment agent (with E2B). |
GROQ_API_KEY | No | Has a slot in the admin panel. No core feature in this release requests it. |
Enrichment
| Variable | Required | What it does |
|---|---|---|
FIRECRAWL_API_KEY | No | Web scraping for contact and target enrichment. Can also be set in the admin panel. |
E2B_API_KEY | No | E2B cloud sandboxes for background target enrichment. |
E2B_ENRICHMENT_TEMPLATE | No | E2B template name. Default: nextcrm-enrichment. |
Details: Enrichment.
Background jobs (Inngest)
| Variable | Required | What it does |
|---|---|---|
INNGEST_ID | Yes | Inngest app id, for example nextcrm. |
INNGEST_APP_NAME | Yes | Display name of the app in Inngest. |
INNGEST_EVENT_KEY | Yes | Key used to send events. In Docker, if empty, generated on the first start and shared with the bundled Inngest server. |
INNGEST_SIGNING_KEY | Yes | Signs and verifies requests between Inngest and /api/inngest. With the bundled server it must be a hex string; in Docker, if empty, it is generated on the first start and shared with the bundled server. With Inngest Cloud use the key from the Inngest dashboard. |
INNGEST_DEV | No | 1 makes the SDK talk to an Inngest dev server and skip signature checks. Only for local development; the compose files set 0. Read by the Inngest SDK. |
INNGEST_BASE_URL | No | Address of the Inngest server, for example http://inngest:8288. Read by the Inngest SDK. |
Details: Background jobs.
Google Calendar
| Variable | Required | What it does |
|---|---|---|
GOOGLE_CALENDAR_CLIENT_ID, GOOGLE_CALENDAR_CLIENT_SECRET | No | OAuth client used when users connect Google Calendar in their profile. Separate from the sign-in client. |
Details: Calendar.
Inbound API and plugins
| Variable | Required | What it does |
|---|---|---|
NEXTCRM_TOKEN | No | Shared secret for the web-to-lead endpoints /api/crm/leads/create-lead-from-web (sent in the Authorization header) and /api/crm/contacts/create-from-remote (sent in a NEXTCRM_TOKEN header). Generate with openssl rand -base64 32. |
PLUGIN_HTTP_ALLOW_PRIVATE_HOSTS | No | true lets plugins make HTTP requests to private hosts. Off by default. |
Seeding
| Variable | Required | What it does |
|---|---|---|
ADMIN_EMAIL | Docker, first start | Email of the first admin. The compose files pass it to the app as TEST_USER_EMAIL. |
TEST_USER_EMAIL | No | Email of the admin user the seed creates or updates. Default test@nextcrm.app. |
SEED_DEMO_DATA | No | 1 adds a small demo dataset (one record per CRM entity). Leave unset on real instances. |
Other
| Variable | Required | What it does |
|---|---|---|
NEXT_PUBLIC_GITHUB_REPO_URL, NEXT_PUBLIC_GITHUB_ISSUES_URL, NEXT_PUBLIC_DISCORD_INVITE_URL | No | Targets of the GitHub, issues and Discord links in the UI. |
NEXT_PUBLIC_GITHUB_REPO_API, NEXT_PUBLIC_GITHUB_TOKEN | No | Used to show the GitHub star count. Leave the token empty. |
NEXT_PUBLIC_NEXT_VERSION | No | Fallback version string in the footer. |
SKIP_ENV_VALIDATION | Build only | The Dockerfile sets it during next build. At runtime it also skips plugin upgrades on boot, so do not set it on a running instance. |
NODE_ENV | Set by the image | production in the Docker image. Outside production the app enables test helpers that expose login codes, so always run real instances with production. |