Skip to content

Configuration reference

Configure a source install or self-hosted server through environment variables. This page lists supported settings, defaults, and precedence.

  • A source install reads .env in the repository folder. Git ignores it. pnpm start creates it from .env.example, readable only by you.
  • The self-hosting stack has its own .env in deployment/self-host/. Keep it private and include it in your backup.
  • For a direct source install, a variable set in your shell wins over the same variable in the repository .env.
  • For the self-hosting stack, put application settings in its private .env. Compose passes all supported model variables from this file through env_file; no edits to compose.yaml are needed. It does not forward arbitrary variables from your host shell. Keep NOD_AUTH_TOKEN, NOD_VAULT_KEY, and NOD_POSTGRES_PASSWORD in .env and unset shell overrides before setup or Compose.
  • Nod reads settings when it starts. After editing .env, apply the configuration changes.
  • Most things don't need a variable. You connect models, apps and channels in the app, and Nod saves them encrypted.
  • The desktop app doesn't read .env. When connected to a server, it uses that server's configuration. Its server address and token are client settings.
flowchart LR
  shell["Direct source:<br/>shell variables"]:::accent -- take precedence over --> file[Repository .env]
  file --> server[Nod server<br/>reads at start]
  compose[Self-host stack .env] --> server
  app[Settings in the app] --> db[(Encrypted<br/>in the database)]
  db --> server

For a Docker installation, run this from the folder containing its .env and compose.yaml:

Terminal
docker compose up -d --wait

If you use the bundled HTTPS proxy, run docker compose --profile https up -d --wait instead. Compose recreates containers whose configuration changed and preserves their data volumes. docker compose restart keeps the old environment values.

For a direct source install, stop and start the Nod process. The desktop app does not read .env; it uses the configuration of the server it connects to.

Variable What it does Default
PORT The local port for the app and API. 4310
NOD_HOST The address the server listens on. Use 0.0.0.0 inside the self-hosting container. A non-loopback address requires NOD_AUTH_TOKEN. 127.0.0.1
NOD_AUTH_TOKEN The access token for the web and desktop clients: at least 43 letters, digits, _, or -. Required for a remote bind or public URL. Never printed in startup logs. Unset; local installs generate a private access key
NOD_DATA_ROOT The folder for local data: sessions, workspace files and the access key. .local
NOD_POSTGRES_PASSWORD The password of the local PostgreSQL container. pnpm start generates one and saves it. A value you set needs at least 43 letters, digits, _ or -. Generated
DATABASE_URL The PostgreSQL connection. pnpm start fills it in for the local container on 127.0.0.1:54329. Set another URL to use your own database. Local container
DATABASE_POOL_MAX The most database connections the server opens. 12
NOD_PUBLIC_URL The exact origin you open Nod at. Remote origins require HTTPS and NOD_AUTH_TOKEN. No path, query, fragment, or user credentials. Loopback origins can use HTTP. http://localhost:<PORT>
NOD_PRIVACY_NOTICE_FILE A Markdown privacy notice served at /privacy. No notice

The access token grants full access to this server's assistant. setup.sh generates it from 32 cryptographically random bytes. For manual setup, use openssl rand -hex 32; a long word or repeated character is not a secure token. Keep it separate from NOD_VAULT_KEY.

Omit NOD_AUTH_TOKEN and NOD_PUBLIC_URL from a local source configuration when you don't set them. An explicitly empty value is invalid. The Docker setup fills both in.

Changing NOD_AUTH_TOKEN and applying the configuration revokes the previous token. Reconnect your web and desktop clients with the new token. See Rotate access.

For a remote server, set both values before starting:

.env
NOD_PUBLIC_URL=https://nod.example.com
NOD_AUTH_TOKEN=<your-generated-token>

Use the self-hosting guide to configure HTTPS and private backing services. Setting a public URL alone does not create a proxy or a certificate.

Keys set here become server-managed connections. They stay in server memory and aren't copied into the database. You can also add connections in Models without any variable. See Models.

Variable What it does Default
LLM_PROVIDER The provider of the first model choice: any supported provider ID. A model you pick in the app takes priority. openai
LLM_MODEL The first model choice. The provider's default
OPENAI_API_KEY Adds an OpenAI connection. It also turns on voice transcription and voice replies. Empty
ANTHROPIC_API_KEY Adds an Anthropic connection. Empty
ANTHROPIC_WORKSPACE_ID The workspace for ANTHROPIC_API_KEY. Required only for organization keys that aren't limited to one workspace. Empty
OPENROUTER_API_KEY Adds an OpenRouter connection with ElevenLabs and Kokoro voices. Also enables transcription when no OpenAI API connection is available. Empty
ELEVENLABS_API_KEY Adds an ElevenLabs connection for account voices and transcription, without a chat model. Empty
OPENAI_COMPATIBLE_BASE_URL Adds an OpenAI-compatible server, such as Ollama at http://localhost:11434/v1. The address must be reachable from Nod's server. Empty
OPENAI_COMPATIBLE_API_KEY The key for that server, if it needs one. Empty
TYPESAFE_API_KEY Selects direct Jev for reading approval replies and checking emails that give account access, regardless of the chat connection. Empty
TTS_MODEL The OpenAI speech model for voice replies. gpt-4o-mini-tts
STT_MODEL The OpenAI or OpenRouter model for incoming voice messages. On OpenRouter, a model ID without / gets the openai/ prefix. gpt-transcribe (openai/gpt-transcribe on OpenRouter)
TTS_VOICE The voice for voice replies. coral

The provider settings table lists every supported key, including GEMINI_API_KEY for Google Gemini and GOOGLE_CLOUD_API_KEY for Vertex AI. It also lists the required Bedrock Region, Azure endpoint and model, and Cloudflare account and gateway settings. You can configure several providers at once; LLM_PROVIDER only sets the initial selection.

Without TYPESAFE_API_KEY, an OpenAI API connection uses GPT Decisions and an OpenRouter connection uses Jev through OpenRouter. Other connections use the selected model for confirmation replies and their smaller background model, when available, for email checks. Your selected model still writes messages. See Decision checks for billing, data routing, and failure behavior.

Voice reuses OpenRouter and OpenAI API keys saved in Models. To connect these services or ElevenLabs, open Settings → General → Voice, choose a Voice provider, then select Connect beside it. Manage opens an existing connection. Set ELEVENLABS_API_KEY for a server-managed ElevenLabs connection; it supplies speech without adding a chat model. Allow Text to Speech, Speech to Text, and Voices read on the key.

Selecting an ElevenLabs account voice uses ElevenLabs for transcription and replies. Otherwise, cloud transcription uses OpenAI, then OpenRouter, then ElevenLabs, depending on which connection is available. You can also download local voices without an API connection.

Nod routes Composio connections through n8n's connection service by default. Users connect each app directly from onboarding or Apps.

Variable What it does Default
NOD_COMPOSIO_PROXY_URL Selects a trusted connection service for source/server installs and isolated desktop development. https://composio.n8n.cloud

Use an HTTPS origin without a path, query, fragment or user credentials. HTTP is allowed only for localhost, 127.0.0.1 or [::1] during local development. Packaged and ordinary source desktop launches use Nod's service; isolated desktop development can override it.

The service operator configures the Composio project and app authorization settings. Those credentials never enter Nod's client configuration. Notion, Linear and n8n connect through their own MCP servers. See Apps.

Variable What it does Default
NOD_VAULT_KEY A base64 32-byte key that encrypts saved credentials. Overrides automatic source-install key storage. The self-hosting stack generates it in .env. Unset for source installs

For an explicitly managed server key, create it with openssl rand -base64 32. Without it, macOS source installs use Keychain, and Linux source installs use NOD_DATA_ROOT/vault/master-key, outside the sandbox. Other source platforms require NOD_VAULT_KEY. The Linux key directory and file must be owned by the server user and private. Desktop uses its OS-protected key.

Nod never generates a replacement when encrypted data already exists. Restore the original key if it is missing. Back up the private key separately alongside the encrypted database; a database backup alone cannot recover saved credentials.

Leave every variable for a channel blank or unset to manage it in Channels. The app checks your account and saves its settings encrypted.

Setting any nonempty variable for a channel makes that entire channel server-managed. Its environment configuration takes precedence over saved settings. The app shows this state and prevents configuration edits or removal.

Set TELEGRAM_ENABLED=false or WHATSAPP_ENABLED=false to disable a channel explicitly. Otherwise, supplying channel settings enables it. Remove or clear every variable for that channel to return to its previous saved setup. Credentials from the environment are never copied into the database.

Variable What it does Default
TELEGRAM_ENABLED true enables Telegram; false disables it. Either value makes the channel server-managed. Unset; follows supplied configuration
TELEGRAM_MODE polling receives messages through outbound requests. webhook needs a public HTTPS address and a registered Telegram webhook. polling for environment-managed setup
TELEGRAM_BOT_TOKEN The bot token from BotFather. Empty
TELEGRAM_WEBHOOK_SECRET_TOKEN The secret Telegram sends with each webhook call: 16 to 256 letters, digits, _ or -. Required for webhook mode. Generated in memory for polling
TELEGRAM_ALLOWED_USER_ID The only Telegram user ID Nod answers. Empty
WHATSAPP_ENABLED true enables WhatsApp; false disables it. Either value makes the channel server-managed. Unset; follows supplied configuration
WHATSAPP_MODE bot links a separate number. self-chat links your own number. cloud uses Meta Cloud API. cloud for environment-managed setup
WHATSAPP_POLICY_CONFIRMED true confirms your use is allowed under the WhatsApp terms. Required. false
WHATSAPP_ACCESS_TOKEN The WhatsApp Cloud API access token from Meta. Empty
WHATSAPP_APP_SECRET The Meta app secret. Nod uses it to check webhook signatures. Empty
WHATSAPP_PHONE_NUMBER_ID The ID of the business sender number. Empty
WHATSAPP_VERIFY_TOKEN The token Meta sends when it verifies the webhook. Empty
WHATSAPP_ALLOWED_NUMBER Your personal number, with country code, 7 to 15 digits. Required for bot and Cloud API. Self-chat uses the linked number. Empty

For QR setup, use Channels to scan the code. The bot and self-chat modes do not use the Meta access token, app secret, business phone number ID or webhook token. The saved device keys stay encrypted in the database. See WhatsApp setup.

The smallest Telegram configuration needs TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_USER_ID; it uses polling.

Set TELEGRAM_MODE=webhook and TELEGRAM_WEBHOOK_SECRET_TOKEN, then apply the configuration. Register the webhook using Telegram's setWebhook method with these fields:

Field Value
url Your public HTTPS origin followed by /api/webhooks/telegram
secret_token The same value as TELEGRAM_WEBHOOK_SECRET_TOKEN
allowed_updates ["message", "message_reaction"]
drop_pending_updates false

Nod does not register environment-managed webhooks for you. Check getWebhookInfo for the saved URL, update types, and delivery errors. Register again after changing the public URL or webhook secret, or to enable reactions on an existing webhook.

To switch to polling, remove the webhook with Telegram's deleteWebhook method, keeping drop_pending_updates=false. Set TELEGRAM_MODE=polling and apply the configuration. Telegram does not allow polling while a webhook is registered.

Variable What it does Default
NOD_ANALYTICS_ENABLED false turns off usage data and recordings for everyone. true turns them on in development too. Each owner still has to opt in. On with pnpm start, off with pnpm run dev
NOD_ANALYTICS_ENVIRONMENT The label on events: production or development. production with NODE_ENV=production, unless NOD_APP_VERSION is a pre-release; desktop sets it to production only for release builds
NOD_FEEDBACK_ENABLED false disables feedback submissions and status checks, regardless of the configured collector. Enabled
NOD_FEEDBACK_URL The HTTPS address that receives Send feedback reports. An empty value turns submission off. The Nod team at n8n
NOD_FEEDBACK_RECEIPT_URL_PREFIX Required with a custom collector. An HTTPS issue collection URL ending in /; receipts must belong to that origin and path. n8n's Linear LAB issues for the default collector
NOD_FEEDBACK_TOKEN Server-only authentication sent as x-nod-feedback-token to the configured feedback collector. Empty
NOD_TRACES_URL The HTTPS address that receives conversation traces from owners who opt in. An empty value turns traces off for everyone. The Nod team at n8n
NOD_TRACES_TOKEN The token sent as x-nod-traces-token with each trace. Without it, Nod sends no traces and hides the switch. Empty; official desktop builds include one

See Analytics and recordings for what's collected.

Analytics go to the Nod team's n8n-owned EU PostHog project, even in independent installations. There is no runtime override for that project. Feedback defaults to https://internal.users.n8n.cloud/webhook/nod/feedback; the dialog identifies the configured recipient before submission. To disable both collectors, set NOD_ANALYTICS_ENABLED=false and NOD_FEEDBACK_ENABLED=false, then apply the configuration. These settings apply to source installs and the desktop process environment. They do not disable model, app or update traffic.

For an operator-owned collector, set NOD_FEEDBACK_URL=https://feedback.example.com/intake and NOD_FEEDBACK_RECEIPT_URL_PREFIX=https://issues.example.com/projects/nod/issues/. A submitted receipt can then link to https://issues.example.com/projects/nod/issues/123, but not another project or origin. Receipt URLs cannot contain credentials, queries, fragments or encoded path separators. The collector uses Nod's existing feedback envelope and receipt contract; setting an endpoint alone does not create a compatible service. NOD_FEEDBACK_TOKEN, when set, supplies the server-only x-nod-feedback-token header. It never goes to the browser or sandbox.

Set OTEL_EXPORTER_OTLP_ENDPOINT to send model request metadata to your own collector. Leave it empty to keep export off.

Variable What it does Default
OTEL_EXPORTER_OTLP_ENDPOINT The base HTTP or HTTPS URL of your OTLP collector. Nod adds /v1/traces. Empty; export off
.env
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318

Apply the configuration after you set or remove the variable. For the desktop app, set it in the process environment before you start Nod. The desktop app does not read .env.

flowchart LR
  Nod[Nod server] --> collector[Your OTLP collector]
  collector --> storage[Your trace storage and dashboards]

Nod sends one span for each model usage record, including helper and background work. Spans contain:

  • The provider and model names, request category, operation, and status.
  • The request start and end times.
  • Available input, output, and cache token counts.
  • Available cost, estimated cost, and pricing source.

Requests from one turn share a trace ID. Exported IDs use a random key that changes when Nod restarts. Nod does not send internal execution IDs.

The export contains no prompts, replies, tool arguments, tool results, keys, or raw errors. Custom model names are included. The collector controls storage, access, and retention.

This export is separate from Share usage data and Share conversation traces. Those switches do not control it. Setting the endpoint enables this export only.

Nod uses OTLP over HTTP with JSON encoding. It sends batches every five seconds and at shutdown. Each request has a five-second timeout. The queue holds at most 256 spans. Failed batches and excess spans are dropped, with no retry. Export does not delay model requests or change spending controls.

This version exports model spans only. It does not export metrics, logs, browser steps, or tool spans. Use your collector to add authentication headers when it forwards spans. Nod does not send authentication headers or support OTLP over gRPC.

Variable What it does Default
WORKSPACE_CONTAINER The Docker container for the workspace. nod-workspace
BROWSER_CONTAINER The Docker container for the browser. nod-browser

The self-hosting stack sets these names to nod-workspace-<project> and nod-browser-<project>, using COMPOSE_PROJECT_NAME for <project>. It gives the server a restricted Docker connection; the workspace and browser receive no Docker socket or provider keys.

In Settings → General → Voice, choose Free voices, then Set up → Download voices, or enable local speech from chat. Nod downloads pinned Whisper and Kokoro models into its data directory and runs them in a separate process on the runtime host. Audio is processed in memory. The worker receives no provider keys or connected account credentials. Local voices speak English, Spanish, French, Hindi, Italian or Brazilian Portuguese. With Assistant voice on Automatic, Nod uses the current speech service and chooses a matching language-specific voice when available. It keeps the service's default when the language is unclear or unsupported. Downloading audio models alone doesn't change a saved voice choice; explicitly choosing Free voices selects local speech once the download finishes. If you connect to a remote Nod server, inference runs on that server.

The default voice uses OpenRouter, then OpenAI, then ElevenLabs, then local speech, depending on which connection is available. Selecting a local voice explicitly uses local speech for both transcription and replies. Nod does not change providers automatically after a failed paid request.

These values belong in deployment/self-host/.env and control Compose. They are separate from the application settings above.

Variable What it does Default
COMPOSE_PROJECT_NAME Names this installation's containers and volumes. Changing it selects different data; use the restore procedure to move an installation. Generated once by setup.sh; existing values are kept
NOD_BIND_ADDRESS Host interface for the backend port. Keep loopback when using Caddy or another local proxy. 127.0.0.1
NOD_IMAGE_TAG Tag assigned to the images built from your checked-out source. It does not download a published release. local
NOD_SERVER_MEMORY Server container's memory limit. 2g
NOD_BROWSER_MEMORY Browser container's memory limit. 3g
NOD_WORKSPACE_MEMORY Workspace container's memory limit. 2g

Compose sets NOD_HOST, NOD_DATA_ROOT, WORKSPACE_CONTAINER, BROWSER_CONTAINER, NODE_ENV, and NOD_ENVIRONMENT for its internal layout. These values override .env in the stack. Store data in the supplied volumes rather than changing container paths.

Set DATABASE_URL only to use an external PostgreSQL server. The bundled database still starts, but Nod uses the external database. The backup and restore commands support the bundled database only.

The packaged server supplies these values. Change them only when you run a custom source layout.

Variable What it does Default
NOD_WEB_ROOT Directory containing the built web app. dist/web
NODE_ENV Use production for a persistent server. Also controls development behavior and analytics defaults. Set by the start command
NOD_ENVIRONMENT Runtime environment label. The conversation-reset development control is available only in development outside production. development

Variables beginning NOD_DESKTOP_ and NOD_TEST_ are internal runtime and test settings. Do not use them to configure a self-hosted server.