Configuration
Environment variables and configuration options for Skilder deployments — backend, frontend, runtime, and infrastructure.
This reference covers the environment variables for each Skilder component.
Backend
The backend runs a Fastify server with Apollo GraphQL.
| Variable | Description | Default |
|---|---|---|
PORT | HTTP port | 3000 |
PRIVATE_DGRAPH_URL | Dgraph database endpoint (internal network) | localhost:8080 |
NATS_SERVERS | NATS server address (this service's own bus connection target) | localhost:4222 |
PUBLIC_NATS_SERVERS | NATS server list advertised to external runtimes | -- |
ENCRYPTION_KEY | Key for encrypting secrets (API keys, OAuth tokens, MCP server configs). Required. | -- |
JWT_PRIVATE_KEY_PATH | Path to Ed25519 private key for signing JWTs | -- |
JWT_PUBLIC_KEY_PATH | Path to Ed25519 public key for verifying JWTs | -- |
JWT_ISSUER | Issuer claim for JWT tokens | skilder-platform |
JWT_ACCESS_TOKEN_TTL | Access token TTL in seconds | 900 (15 min) |
JWT_REFRESH_TOKEN_TTL | Refresh token TTL in seconds | 604800 (7 days) |
IDENTITY_KEY_USAGE_THROTTLE_SECONDS | How long an identity key's recorded "last used" timestamp counts as fresh before it is written again | 60 (1 minute) |
LOG_LEVEL | Logging verbosity: trace, debug, info, warn, error | info |
CORS_ORIGINS | Allowed CORS origins (comma-separated) | http://localhost:8888,http://localhost:3000 |
PRIVATE_MCP_URL | Remote MCP server endpoint reached over the internal network | http://localhost:3001/mcp |
PUBLIC_BACKEND_URL | Externally-reachable backend base URL (OAuth issuer/endpoints, MCP server URLs, signed file URLs). Must never be an internal service name. Required in production. | http://localhost:3000 |
PUBLIC_FRONTEND_URL | Public frontend URL (used for email links, OAuth callbacks) | http://localhost:8888 |
PUBLIC_MCP_URL | Public, externally-reachable MCP URL of the remote MCP server (RFC 8707 resource identifier advertised in OAuth metadata) | http://localhost:3001/mcp |
EMAIL_PROVIDER | Email provider: log (console), brevo (EU), or resend (US) | log |
BREVO_API_KEY | Brevo API key (when EMAIL_PROVIDER=brevo) | -- |
RESEND_API_KEY | Resend API key (when EMAIL_PROVIDER=resend) | -- |
EMAIL_FROM | Sender email (when EMAIL_PROVIDER=brevo or resend) | -- |
EMAIL_FROM_NAME | Sender display name (used by Brevo) | The Skilder Team |
BREVO_TIMEOUT_SECONDS | Per-request timeout for the Brevo API, in seconds | 10 |
Example
PORT=3000
PRIVATE_DGRAPH_URL=localhost:8080
NATS_SERVERS=localhost:4222
ENCRYPTION_KEY=your-64-char-hex-encryption-key
JWT_PRIVATE_KEY_PATH=./keys/private.pem
JWT_PUBLIC_KEY_PATH=./keys/public.pem
JWT_ISSUER=skilder-platform
LOG_LEVEL=info
CORS_ORIGINS=https://app.yourdomain.com
PRIVATE_MCP_URL=http://localhost:3001/mcp
PUBLIC_BACKEND_URL=https://app.yourdomain.com
PUBLIC_FRONTEND_URL=https://app.yourdomain.com
EMAIL_PROVIDER=brevo
BREVO_API_KEY=xkeysib-your_api_key_here
EMAIL_FROM=noreply@mail.skilder.ai
EMAIL_FROM_NAME=The Skilder TeamFrontend
The frontend is a React + Vite application.
| Variable | Description | Default |
|---|---|---|
VITE_PUBLIC_BACKEND_URL | Externally-reachable backend base URL (build-time). Full URL including scheme. | http://localhost:3000 |
PUBLIC_BACKEND_URL | Backend base URL (runtime, Docker). Injected into the served HTML via window.__ENV__; overrides VITE_PUBLIC_BACKEND_URL. | -- |
The frontend derives HTTP and WebSocket URLs from the backend URL automatically.
Example
# Build-time
VITE_PUBLIC_BACKEND_URL=https://api.yourdomain.com
# Runtime (Docker)
PUBLIC_BACKEND_URL=https://api.yourdomain.comRuntime
The runtime executes MCP servers and routes tool calls. Its mode is determined by which environment variables are set.
Identity
A runtime needs RUNTIME_KEY, or SYSTEM_KEY together with RUNTIME_NAME. There are no modes left to select — a runtime executes tools, and the public MCP endpoint is its own service.
Two variables are rejected at boot rather than ignored:
USER_KEY— the former stdio single-agent mode. Connect agents to the Streamable HTTP endpoint instead.MCP_REMOTE_ENABLED— the former fused MCP mode. Run the remote MCP server for that.
REMOTE_PORT controls the web service (GET /health for liveness, GET /ready for readiness) and nothing else.
Core Configuration
| Variable | Description | Default |
|---|---|---|
NATS_SERVERS | NATS cluster address | localhost:4222 |
REMOTE_PORT | Port for the web service — GET /health and GET /ready | -- (no web service; container images default to 3003) |
RUNTIME_NAME | Human-readable name (required with SYSTEM_KEY) | -- |
LOG_LEVEL | Logging verbosity | info |
LOG_LEVELS | Pattern-based log levels (e.g., mcp.*=debug,tool.*=trace) | -- |
FORWARD_STDERR | Forward child process stderr to runtime log | false |
HEARTBEAT_INTERVAL | Health heartbeat interval in ms | 5000 |
PRIVATE_MCP_URL | Remote MCP server address (internal network) the delegate tool dials back. Optional: unset, the runtime uses the public MCP URL the backend advertises at handshake | http://localhost:3001/mcp |
File Service
| Variable | Description | Default |
|---|---|---|
SKILDER_WORKING_DIR | Working directory for temp files and assets | /tmp/skilder |
SKILDER_ALLOWED_PATHS | Colon-separated path safelist for file access | -- |
SKILDER_MAX_FILE_SIZE_MB | Max file size for operations | 10 |
SKILDER_GC_INTERVAL_MS | Garbage collection check interval | 60000 (1 min) |
SKILDER_GC_MAX_AGE_MS | Max age for temp files before cleanup | 300000 (5 min) |
SKILDER_ASSET_CACHE_MAX_AGE_MS | Asset cache TTL | 3600000 (1 hour) |
Example
RUNTIME_KEY=RTK_your_runtime_key
NATS_SERVERS=nats://nats.yourdomain.com:4222
REMOTE_PORT=3003
PRIVATE_MCP_URL=http://remote-mcp:3001/mcp
LOG_LEVEL=info
SKILDER_WORKING_DIR=/tmp/skilderRemote MCP Server
The public Streamable HTTP surface agents connect to. It terminates agent HTTP and OAuth, holds MCP sessions, and fans every tool call out to runtimes over NATS — it executes nothing itself.
Identity
SYSTEM_KEY, and only SYSTEM_KEY. It handshakes as a remote-mcp-server identity: no Runtime row, no heartbeat, no workspace of its own (each session carries one). RUNTIME_KEY and RUNTIME_NAME are rejected at boot — accepting them would register a phantom runtime the backend would then route work to.
Core Configuration
| Variable | Description | Default |
|---|---|---|
NATS_SERVERS | NATS cluster address | localhost:4222 |
REMOTE_PORT | Port for /mcp, /health, /ready and the OAuth metadata. Required | -- (container images default to 3001) |
PRIVATE_BACKEND_URL | Backend HTTP base for catalog pulls and transient uploads | handshake-advertised URL |
PUBLIC_MCP_URL | This server's public, externally-reachable MCP URL (RFC 8707 resource identifier) | http://localhost:3001/mcp |
PUBLIC_BACKEND_URL | Public base URL of the Authorization Server, advertised in the resource metadata | http://localhost:3000 |
LOG_LEVEL / LOG_LEVELS | Logging verbosity | info |
Preloading
Preloading is per MCP session, not per process: append ?skillIds=<id,id> or ?roleIds=<id,id> to the /mcp endpoint URL to auto-disclose those skills or roles to that connection. The SKILL_IDS / ROLE_IDS environment variables belonged to the removed stdio mode and are no longer read (SKI-605).
Security
| Variable | Description | Default |
|---|---|---|
SKILDER_ALLOWED_ORIGINS | Allowed origins for the HTTP transport | -- |
SKILDER_PREVENT_DNS_REBINDING | Enable origin validation against DNS rebinding | true |
SKILDER_SESSION_IDLE_TIMEOUT_MS | Session cleanup timeout | 300000 (5 min) |
Example
SYSTEM_KEY=SYK_your_system_key
NATS_SERVERS=nats://nats.yourdomain.com:4222
REMOTE_PORT=3001
PUBLIC_MCP_URL=https://mcp.yourdomain.com/mcp
PUBLIC_BACKEND_URL=https://api.yourdomain.com
SKILDER_ALLOWED_ORIGINS=https://app.yourdomain.comInfrastructure Services
Dgraph (Graph Database)
Deploy with at least one Zero node and one Alpha node.
| Port | Description | Default |
|---|---|---|
| Alpha HTTP | Query and mutation endpoint | 8080 |
| Alpha gRPC | Internal replication | 9080 |
| Zero gRPC | Cluster coordination | 5080 |
NATS (Message Bus)
| Variable | Description | Default |
|---|---|---|
NATS_PORT | Client connection port | 4222 |
NATS_HTTP_PORT | HTTP monitoring port | 8222 |
NATS_JETSTREAM | Enable JetStream for persistent messaging | true |
Security Notes
- Never commit secrets to version control. Use a secrets manager or
.envfiles. - Change the default
ENCRYPTION_KEYimmediately. The default key is for development only — using it in production compromises all encrypted data. - Generate a strong
ENCRYPTION_KEY: 64-character hex string (32 random bytes). - Set up JWT keys: Generate an Ed25519 key pair for JWT signing. See
agent_docs/key-management.mdfor details. - Restrict
CORS_ORIGINSin production to your exact frontend domain. - Use TLS for NATS and Dgraph connections in production.

