Administration¶
Audience: Administrators, Developers · Tags:
admin,configuration,environment,operator
This page is the operator's guide to configuring a SnapLink backend instance.
SnapLink is configured entirely through environment variables (typically a
.env file, or your platform's secret/config store) — there is no
admin-panel equivalent for most of these yet. Every variable below is real:
its name and default match backend/.env.example exactly. Nothing here is
aspirational.
For the customer-facing side of administration (workspaces, members, roles), see Missing permissions and Security.
Server¶
| Variable | Default | Purpose |
|---|---|---|
NODE_ENV |
— | development or production. Affects logging verbosity and error detail. |
PORT |
4000 |
The port the API listens on. |
CORS_ORIGINS |
— | Comma-separated list of frontend origins allowed to call the API from a browser. |
LOG_LEVEL |
info |
Log verbosity (e.g. info, debug). |
Persistence¶
| Variable | Default | Purpose |
|---|---|---|
DB_DRIVER |
memory |
memory (non-durable, in-process) or postgres (durable). |
DATABASE_URL |
— | Required when DB_DRIVER=postgres. Standard Postgres connection string. |
DATABASE_SSL |
true |
true for managed/Supabase Postgres; false for a local Docker Postgres instance without certificates. |
Memory vs Postgres — read this before you deploy anything real. With
DB_DRIVER=memory(the default), every account, workspace, flow, connection, and run lives in a process-local in-memory store. It is fast to boot and perfect for a demo, an evaluation instance, or local development — and it is wiped on every restart (deploy, crash, scale event, or plainCtrl+C). Never point real users, real connectors, or anything you need to keep at a memory-mode instance. SetDB_DRIVER=postgreswith a realDATABASE_URLto make the instance durable.
Auth¶
| Variable | Default | Purpose |
|---|---|---|
SUPABASE_URL |
— | Recorded alongside the JWT secret; part of the auth boundary configuration. |
SUPABASE_JWT_SECRET |
— | The HS256 secret SnapLink's backend uses to sign and verify its own bearer tokens. Required — without it, the API fails closed and every request is rejected. |
SnapLink's login/signup is self-issued, not delegated to Supabase: when
a user signs up or logs in (POST /auth/signup, POST /auth/login), the
backend itself issues an HS256 JWT (default lifetime 7 days) signed with
SUPABASE_JWT_SECRET, and verifies that same signature on every subsequent
request. The variable name is a holdover from an earlier Supabase-Auth
integration; the secret today is purely SnapLink's own signing key. Generate
a long, random value and treat it exactly like any other signing secret —
rotating it invalidates every existing session token.
If this variable is missing or empty, requests fail with a 500
AUTH_NOT_CONFIGURED error rather than an open/anonymous fallback — SnapLink
fails closed on purpose.
AI / Snap Studio¶
| Variable | Default | Purpose |
|---|---|---|
AI_PROVIDER_API_KEY |
— | Enables Snap Studio's real-LLM drafting engine (engine: "llm"). |
AI_PROVIDER_MODEL |
claude-opus-4-8 |
Model id (first-party Anthropic) or, when using Azure AI Foundry, the Foundry deployment name. |
AI_FOUNDRY_BASE_URL |
— | Optional. Routes Studio's drafting agent through an Azure AI Foundry Anthropic-compatible endpoint instead of the first-party Anthropic API. |
Snap Studio's drafting assistant (Describe → Review → Save & test) turns a
plain-English prompt into a flow plan. Without AI_PROVIDER_API_KEY set,
Studio does not error or degrade visibly — it automatically and silently
falls back to a deterministic, keyword-based rules planner (engine:
"rules"). This is a normal operating mode, not a broken state; every plan
response reports which engine produced it via its engine field.
Azure AI Foundry option. Set AI_FOUNDRY_BASE_URL to your Foundry
resource's Anthropic-compatible endpoint, e.g.:
AI_FOUNDRY_BASE_URL=https://<your-foundry-resource>.services.ai.azure.com/anthropic
When set, AI_PROVIDER_API_KEY holds your Foundry key and
AI_PROVIDER_MODEL holds the Foundry deployment name (e.g.
claude-sonnet-4-6) rather than a first-party Anthropic model id. Leave
AI_FOUNDRY_BASE_URL unset to use the first-party Anthropic API directly.
What's sent to the model. Only the user's own prompt text plus a static description of SnapLink's connector catalog. AI provider keys are never logged, and no workspace data, run data, or connector credentials are ever included in a drafting request.
Security, SSRF & rate limits¶
| Variable | Default | Purpose |
|---|---|---|
REST_ALLOW_PRIVATE_NETWORK |
false |
SSRF guard for the REST connector. Must stay false in production. Only for local dev/testing against loopback targets. |
RATE_LIMIT_WINDOW_SECONDS |
60 |
Fixed-window size for webhook ingress rate limiting. |
RATE_LIMIT_PER_ENDPOINT |
120 |
Max webhook requests per flow's endpoint, per window. |
RATE_LIMIT_PER_IP |
240 |
Max webhook requests per source IP, per window. |
RATE_LIMIT_PER_WORKSPACE |
600 |
Max webhook requests per workspace, per window. |
Rate limiting applies to webhook ingress, not general authenticated API traffic. It is a fixed-window limiter (no external dependency required) — see Rate limiting for the customer-facing behavior and how to raise these limits.
Secrets & infra¶
| Variable | Default | Purpose |
|---|---|---|
CREDENTIAL_ENCRYPTION_KEY |
— | 32-byte, base64-encoded key used to encrypt connector credentials at rest. |
SECRET_PROVIDER |
memory |
memory (dev, not encrypted) | encrypted (AES-256-GCM at rest, requires CREDENTIAL_ENCRYPTION_KEY) | azure (documented seam). |
INFRA_BACKEND |
memory |
Cache / rate-limit backing store: memory or redis. |
REDIS_URL |
— | Required when INFRA_BACKEND=redis. |
Generate CREDENTIAL_ENCRYPTION_KEY once per environment and store it
outside source control (secret manager, platform env config). Losing it
means existing encrypted credentials can no longer be decrypted.
Async / distributed execution seam¶
| Variable | Default | Purpose |
|---|---|---|
ASYNC_MODE |
custom |
off | events | commands | full | custom — the unified knob for the async/queue seam. |
ASYNC_ADAPTER |
inprocess |
inprocess or rabbitmq. |
RABBITMQ_URL |
— | Required when ASYNC_ADAPTER=rabbitmq; otherwise unused. |
This seam is disabled by default and optional — core flow execution
works fully without it. It exists for distributed-execution deployments that
want to move triggering/dispatch onto an event bus or command queue instead
of handling everything in-process. (Two lower-level flags,
ASYNC_EVENT_BUS_ENABLED and ASYNC_COMMAND_QUEUE_ENABLED, also exist and
are what ASYNC_MODE derives under the hood — operators should set
ASYNC_MODE and leave those alone unless you have a specific reason not to.)
SMTP (Email connector)¶
The Email connector sends through SMTP configured by the operator, not by
individual flow authors: SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS,
SMTP_FROM. See Email connector for provider
setup (Gmail, Brevo, Mailtrap) and troubleshooting. If these aren't set,
Email actions fail at runtime with error code auth.
CORS configuration¶
CORS_ORIGINS is a comma-separated allowlist of the exact frontend origins
(scheme + host + port) permitted to call the API from a browser, e.g.:
CORS_ORIGINS=https://app.example.com,http://localhost:5173
If a frontend origin isn't listed here, browser requests from it are blocked by CORS before they reach your handlers — this is the single most common cause of "my frontend can't reach the API" during setup. Update this list whenever you add a new frontend deployment (staging, a new custom domain, a local dev port).
Secrets hygiene checklist¶
- Never commit a real
.envfile. Commit only.env.examplewith empty/placeholder values. - Bearer tokens and connector credentials are never logged and never echoed back in API responses.
- SMTP passwords and AI provider keys belong in operator environment config only — never paste them into a flow's fields.
- Treat
SUPABASE_JWT_SECRETandCREDENTIAL_ENCRYPTION_KEYas high-value secrets: generate them randomly, store them in your platform's secret manager, and restrict who can read them. - Rotating
SUPABASE_JWT_SECRETinvalidates every existing session (all users are signed out). Plan for that.
What's NOT configurable yet¶
Being direct about the current edges, so you can plan around them:
- No per-workspace SMTP. SMTP is a single, instance-wide operator setting — every workspace on this instance shares it. Per-workspace mail configuration is Planned.
- No SSO/SAML. Login is SnapLink's own email/password auth only.
- No roles beyond owner / admin / member. There is no custom-role editor.
- No billing tiers or usage quotas enforced at the environment-variable level.
- No uptime SLA or compliance certification (e.g. SOC 2) — see Security for the honest current posture.
- No published OpenAPI spec file yet — see API Reference for the hand-written endpoint list.
Example .env¶
A realistic starting point for a Postgres-backed, encrypted-secrets instance
with first-party Anthropic AI drafting enabled. Replace every value marked
<...> — do not reuse these as real secrets.
NODE_ENV=production
PORT=4000
CORS_ORIGINS=https://app.example.com
LOG_LEVEL=info
DB_DRIVER=postgres
DATABASE_URL=postgres://snaplink:<db-password>@db.internal:5432/snaplink
DATABASE_SSL=true
SUPABASE_URL=https://<project>.supabase.co
SUPABASE_JWT_SECRET=<long-random-signing-secret>
CREDENTIAL_ENCRYPTION_KEY=<32-byte-base64-key>
SECRET_PROVIDER=encrypted
AI_PROVIDER_API_KEY=<anthropic-api-key>
AI_PROVIDER_MODEL=claude-opus-4-8
# AI_FOUNDRY_BASE_URL=https://<your-foundry-resource>.services.ai.azure.com/anthropic
REST_ALLOW_PRIVATE_NETWORK=false
RATE_LIMIT_WINDOW_SECONDS=60
RATE_LIMIT_PER_ENDPOINT=120
RATE_LIMIT_PER_IP=240
RATE_LIMIT_PER_WORKSPACE=600
INFRA_BACKEND=memory
REDIS_URL=
ASYNC_MODE=custom
ASYNC_ADAPTER=inprocess
RABBITMQ_URL=
SMTP_HOST=smtp-relay.brevo.com
SMTP_PORT=587
SMTP_USER=<smtp-user>
SMTP_PASS=<smtp-password>
SMTP_FROM=notifications@example.com
Related: Security · Email connector · API Reference · Missing permissions
Was this helpful? 👍 👎