Environment Variables
Infrastructure configuration — the database, storage, ports and secrets. Everything a request can change lives in Settings instead.
Environment variables configure infrastructure: where the database is, where tenant content is written, which ports to bind, and the secrets the backend needs. They are read at startup and need a restart to change.
Everything else — provider keys, model choice, agent behaviour, sandbox mode — lives in the store and is edited in Settings. The split is deliberate: infrastructure is set by whoever deploys the instance, and settings are changed by whoever uses it.
Copy .env.example to .env in the repo root and edit what you need. Every value is optional; SynapseOrch runs on defaults with nothing configured.
cp .env.example .envThe .env file at the project root is loaded at startup, and real environment variables win — a value already set in the environment is not overridden by the file. That is what makes a container's environment authoritative over a .env that happened to be copied into the image.
Provider API keys are not environment variables
OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_SECRET_ACCESS_KEY and the old
SYNAPSE_SETTING_* overlay are no longer read. Provider credentials are
held in the store, read per call for the tenant in context, and never written
to the process environment.
This is a security boundary, not housekeeping. Anything in the environment is
readable through /proc/<pid>/environ and is inherited by every subprocess —
and this engine spawns stdio MCP servers and a code sandbox, which would
otherwise have been handed every key the process held. Enter provider keys
under Settings → Models.
Storage
Three variables decide where state lives. A plain install needs none of them.
SYNAPSE_HOME — the folder an installed SynapseOrch keeps everything in: its data, .env, logs and backups. Default ~/.synapse (%USERPROFILE%\.synapse on Windows). The defaults below sit under its var/. See the CLI.
SYNAPSE_DB_URL — the database holding settings, agents, workflows, tools, schedules, runs and usage. Defaults to SQLite at ~/.synapse/var/synapse.db in an installed SynapseOrch ($SYNAPSE_HOME/var), backend/var/synapse.db in a source checkout and /data/synapse.db in the single-container image, so a fresh install needs nothing running. Point it at Postgres for any deployment serving more than one process:
SYNAPSE_DB_URL=postgresql://user:pass@host:5432/synapseA postgresql:// or postgres:// URL is converted to the postgresql+asyncpg:// driver form at startup, so either spelling works.
SYNAPSE_BLOB_DIR — where tenant content is written: the vault, run logs, cached responses. Defaults to ~/.synapse/var/blobs in an installed SynapseOrch ($SYNAPSE_HOME/var), backend/var/blobs in a source checkout, /data/blobs in the single-container image and /blobs in Docker Compose. Processes that serve the same data — a main instance and scale mode workers — must share this directory, unless they are all configured with the same bucket (below), which replaces it.
SYNAPSE_STATE_DIR — rebuildable per-replica state, currently the ChromaDB index. Defaults to ~/.synapse/var/state in an installed SynapseOrch ($SYNAPSE_HOME/var), backend/var/state in a source checkout. Losing it costs a re-index, not data, so each replica in a multi-replica deployment should have its own rather than sharing one.
Object storage
With a bucket configured, an S3 or S3-compatible store (MinIO, R2) is the blob store: the vault, run logs, notifications and cached responses are written there instead of SYNAPSE_BLOB_DIR, in the API server, in every worker and in the tool processes they start. Keys are <S3_PREFIX>/<tenant>/…. Nothing already on disk is copied across. The same values can be saved in Settings → Scale instead; the variables win. See Scale Configuration → S3 storage.
| Variable | Notes |
|---|---|
S3_BUCKET | Required — set it, and the bucket is the blob store |
S3_REGION | |
S3_ENDPOINT_URL | Set for MinIO, R2 and other S3-compatible services |
S3_ACCESS_KEY_ID | |
S3_SECRET_ACCESS_KEY | |
S3_PREFIX | Optional key prefix, if the bucket is shared |
Upgrading from SYNAPSE_DATA_DIR
Before 2.0 a single DATA_DIR held everything — JSON documents, tenant content and real directories in one tree. It is no longer a runtime path. On first boot SynapseOrch looks for an existing data directory and imports it into the store; see Store and upgrade.
SYNAPSE_DATA_DIR is still read for exactly that: if your deployment sets it, the importer uses it to find the tree to import. It configures nothing afterwards.
Ports and URLs
SYNAPSE_BACKEND_PORT — the FastAPI backend. Default 8765.
SYNAPSE_FRONTEND_PORT — the Next.js frontend. Default 3000.
BACKEND_URL — the backend as the Next.js server sees it, read when that server starts. Unset, it is http://127.0.0.1: and the port in SYNAPSE_BACKEND_PORT, or 8765 if that is unset too. Changing it needs a restart of the frontend, not a rebuild. Set it for Docker or split deployments, for example http://synapse-backend:8765.
CORS_ORIGINS — comma-separated origins the backend accepts. Default http://localhost:3000,http://localhost:5173. Add your own origin when hosting on a custom domain.
OLLAMA_BASE_URL — the Ollama server for local models. Default http://127.0.0.1:11434. See Local models.
Secrets
SYNAPSE_JWT_SECRET — signs login session tokens. Auto-generated and persisted to .env on the first synapse start. Set it explicitly for stateless container deployments where .env does not survive, or every restart invalidates every session.
SYNAPSE_INTERNAL_TOKEN — gates /api/* and root /chat so that only the frontend can reach them. The frontend sends it as an X-Synapse-Internal header on every proxied request; direct callers without it get a 403. It proves a request came through the frontend, not who sent it: while login is on or an access link is set, the backend also wants a signed-in session, and answers 401 Login required without one. The externally authenticated APIs (/api/v1, /api/v2) are exempt and use API keys instead.
When it is not set the backend falls back to loopback-only: requests whose direct peer is 127.0.0.1 or ::1 are allowed and every remote caller is refused. synapse start and the Docker images generate a token automatically, so this fallback applies only to a backend started some other way.
SYNAPSE_ACCESS_TOKEN — the token in this install's access link, which opens Synapse while login is off. synapse start generates it into .env and the Docker images onto the data volume; set it yourself to pin one. With it unset and login off, anyone who can reach the app's port can use Synapse.
Set a token on anything network-reachable
A backend with no token, login disabled and stdio MCP registration allowed is
the exact posture of GHSA-3j67-x3j8-r32x, where registering an MCP server
executes local commands. The backend warns loudly at startup when it starts
in that state. Set SYNAPSE_INTERNAL_TOKEN, enable login, or set
allow_stdio_mcp=false — see Settings.
Note that the loopback check compares the peer address, and a browser on the Windows host reaching a WSL backend arrives as ::ffff:127.0.0.1 rather than 127.0.0.1. Set the token on both processes for that setup or every call 403s.
Egress
EGRESS_ALLOW_HOSTS — comma-separated host names that custom HTTP tools, the web scraper and the PDF and Excel parsers and a knowledge base's web crawls may call even though they resolve to loopback or private address space. Empty by default, which refuses them all. Use it for a service on your own network — a self-hosted n8n, an intranet API — and name the host as the tool's URL spells it:
EGRESS_ALLOW_HOSTS=localhost,n8n,api.internal.company.comA refused call says which host it was and names this variable. Changing it takes a restart.
Timeouts
All in seconds unless the name says otherwise. Each falls back to the value it had before it was made configurable, so leaving them unset changes nothing. Raise them for slow networks or slow local models; lower them to fail fast.
| Variable | Default | Applies to |
|---|---|---|
SYNAPSE_LLM_TIMEOUT | 180 | One attempt at a cloud LLM call |
SYNAPSE_HTTP_TOOL_TIMEOUT | 30 | A custom HTTP or webhook tool call |
SYNAPSE_MCP_SESSION_READ_TIMEOUT | 60 | Any MCP request |
SYNAPSE_MCP_TOOL_CALL_TIMEOUT | 60 | A single MCP tool invocation |
SYNAPSE_MCP_LIST_TOOLS_TIMEOUT | 15 | Discovering a server's tools |
SYNAPSE_ORCH_STEP_TIMEOUT | 300 | A step that sets no timeout of its own |
SYNAPSE_ORCH_GLOBAL_TIMEOUT_MINUTES | 30 minutes | A workflow that sets no timeout of its own |
SYNAPSE_ORCH_HUMAN_TIMEOUT | 3600 | The default of a human gate's Timeout (seconds): how long a reply in its messaging channel answers it. The gate itself waits until it is answered |
Workflows
SYNAPSE_PARALLEL_MAX_BRANCHES — how many branches of a Parallel step run at the same time. Default 4.
SYNAPSE_PARALLEL_BRANCHES — 0 runs every branch of a Parallel step one after another. Default on.
Telemetry
Off unless you turn it on; nothing is ever sent to us. See Telemetry for what each exports.
| Variable | Effect |
|---|---|
OTLP_ENDPOINT | Turns OpenTelemetry export on, to this collector |
SYNAPSE_TELEMETRY | otlp turns it on, to OTEL_EXPORTER_OTLP_ENDPOINT; off keeps it off whatever else is set |
OTEL_SDK_DISABLED | true keeps it off whatever else is set |
METRICS_TOKEN | Serves Prometheus metrics at GET /api/v2/metrics, with this as the Bearer token |
SYNAPSE_LOG_FORMAT | json writes JSON log lines carrying the trace, run, session and request ids |
The CLI's client commands
The CLI's commands that drive a Synapse — synapse run, synapse runs, synapse chat, synapse mcp and the rest — read these. The command line's --url and --api-key win over them.
| Variable | Default | Effect |
|---|---|---|
SYNAPSE_API_URL | This machine's backend | The Synapse to drive — an origin such as https://api.synapseorch.com; the CLI adds /api/v1 |
SYNAPSE_API_KEY | — | The API key to use. A remote Synapse needs one; this machine's does not |
SYNAPSE_CLI_CONFIG | ~/.synapse/cli.json | Where the CLI keeps its own key and its login |
SYNAPSE_CHAT_HISTORY | ~/.synapse/chat_history | synapse chat's input history |
Knowledge
How knowledge bases read files. Each file is read in a separate process, which sees these variables and a short list of others — never a database URL or a provider key.
| Variable | Default | |
|---|---|---|
SYNAPSE_KNOWLEDGE_PARSE_TIMEOUT_S | 1800 | Seconds one file may take to read; the pages read by then are kept |
SYNAPSE_KNOWLEDGE_PARSE_MEMORY_MB | 1024 | Memory for reading one file |
SYNAPSE_KNOWLEDGE_DOCLING_MEMORY_MB | 2048 | Memory for reading one PDF with the knowledge extra's layout reader |
SYNAPSE_KNOWLEDGE_DOCLING_BATCH_PAGES | 4 | Pages that reader takes at a time |
SYNAPSE_KNOWLEDGE_OCR_TIMEOUT_S | 900 | Seconds for reading one file's scanned pages, where OCR is configured |
SYNAPSE_KNOWLEDGE_CONTEXT_CONCURRENCY | 4 | Contextual Retrieval calls at once |
DOCLING_ARTIFACTS_PATH | models/docling under the state directory | Where the layout reader's downloaded models are |
SYNAPSE_SOFFICE | soffice or libreoffice on PATH | LibreOffice, for legacy .doc, .xls and .ppt files |
Other
SYNAPSE_LOG_LEVEL — backend log verbosity. Default INFO.
SYNAPSE_PROFILING — enables performance profiling. Default off; synapse start --profile sets it for you. See the CLI.
REDIS_URL — the Redis instance for scale mode. Overrides the redis_url setting. Setting it is what turns scale mode on — there is no separate switch in the environment.
SCALE_POSTGRES_URL — optional. The URL the scale layer connects with, overriding the scale_postgres_url setting. Unset, it uses SYNAPSE_DB_URL, which is what most deployments want: it is the same database, and the scale-side name only predates the store. If you do set it, point it at that same Postgres.
SYNAPSE_TENANT_ID — the tenant a process serves. A single-tenant install never sets this; it exists for deployments that run the engine per tenant.
DATABASE_URL — present in .env.example but read by nothing. The database the SQL agent and the code indexer query is configured in Settings as sql_connection_string, deliberately never from the environment. Setting DATABASE_URL has no effect.