Environment Variables
Complete environment variable reference
Environment Variables
Stevora uses a Zod-validated environment configuration loaded at startup. If any required variable is missing or invalid, the server will refuse to start and print a clear error message indicating which variables need attention.
All environment variables are defined in src/config/env.ts and validated against a strict schema.
Quick Start
Copy the example file and fill in your values:
cp .env.example .envFor production deployments:
cp .env.production.example .env.productionAt minimum, you need to set DATABASE_URL to a valid PostgreSQL connection string. Everything else has sensible defaults for local development.
Full Reference
Application
| Variable | Description | Default | Required |
|---|---|---|---|
NODE_ENV | Runtime environment. Must be development, production, or test. | development | No |
PORT | Port the API server listens on. | 3000 | No |
HOST | Host address to bind. Use 0.0.0.0 to accept connections from any interface. | 0.0.0.0 | No |
LOG_LEVEL | Pino log level. One of: fatal, error, warn, info, debug, trace. | info | No |
Database
| Variable | Description | Default | Required |
|---|---|---|---|
DATABASE_URL | PostgreSQL connection string. Must be a valid URL. Example: postgresql://user:password@host:5432/dbname?schema=public | -- | Yes |
DATABASE_URL is the only strictly required variable. The server will not start without it. For managed databases (RDS, Neon, Supabase), use the connection string provided by your provider. Always include ?schema=public at the end.
Redis
Redis is used by BullMQ for job queues. The worker requires a Redis connection to process workflow steps.
| Variable | Description | Default | Required |
|---|---|---|---|
REDIS_HOST | Redis server hostname. | localhost | No |
REDIS_PORT | Redis server port. | 6379 | No |
REDIS_PASSWORD | Redis authentication password. Leave empty for no auth. | -- | No |
REDIS_DB | Redis database index (0-15). | 0 | No |
If you are using Upstash Redis, set REDIS_HOST to your Upstash endpoint (e.g., your-instance.upstash.io) and REDIS_PASSWORD to your Upstash token. The default port 6379 works for most providers.
API Rate Limiting
The API server applies per-key rate limiting to protect against abuse.
| Variable | Description | Default | Required |
|---|---|---|---|
API_RATE_LIMIT_MAX | Maximum number of requests per window per API key. | 100 | No |
API_RATE_LIMIT_WINDOW_MS | Rate limit window duration in milliseconds. | 60000 (1 minute) | No |
For example, the defaults allow 100 requests per minute per API key. To allow higher throughput for production workloads:
API_RATE_LIMIT_MAX=1000
API_RATE_LIMIT_WINDOW_MS=60000LLM Providers
LLM API keys are optional at the infrastructure level. They are only needed if your workflows use llm type steps. Stevora supports both OpenAI and Anthropic models.
| Variable | Description | Default | Required |
|---|---|---|---|
OPENAI_API_KEY | OpenAI API key for GPT models (gpt-4o, gpt-4o-mini, etc.). | -- | No |
ANTHROPIC_API_KEY | Anthropic API key for Claude models (claude-sonnet-4-20250514, etc.). | -- | No |
You only need the keys for the providers your workflows actually use. If all your workflows use Claude, you only need ANTHROPIC_API_KEY. If a workflow specifies a model from a provider whose key is not configured, the step will fail with a clear error.
Dashboard and Admin
| Variable | Description | Default | Required |
|---|---|---|---|
DASHBOARD_URL | URL where the Stevora dashboard is hosted. Used for CORS and approval links. | http://localhost:3001 | No |
ADMIN_TOKEN | Token for admin-level API operations (managing workspaces, viewing all runs). | -- | No |
Observability
| Variable | Description | Default | Required |
|---|---|---|---|
SENTRY_DSN | Sentry Data Source Name for error tracking. When set, unhandled errors and failed workflow steps are reported to Sentry. | -- | No |
OTEL_EXPORTER_OTLP_ENDPOINT | OpenTelemetry collector endpoint for distributed tracing. Example: http://localhost:4318. | -- | No |
When OTEL_EXPORTER_OTLP_ENDPOINT is set, the server exports traces in OTLP format. This works with any OpenTelemetry-compatible backend: Jaeger, Grafana Tempo, Honeycomb, Datadog, etc.
Example Configurations
Local Development
NODE_ENV=development
PORT=3000
HOST=0.0.0.0
LOG_LEVEL=debug
DATABASE_URL=postgresql://stevora:stevora@localhost:5432/stevora?schema=public
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
OPENAI_API_KEY=sk-your-dev-key
ANTHROPIC_API_KEY=sk-ant-your-dev-keyProduction (Managed Services)
This example uses AWS RDS for PostgreSQL and Upstash for Redis:
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
LOG_LEVEL=info
DATABASE_URL=postgresql://stevora:YOUR_PASSWORD@your-rds-instance.us-east-1.rds.amazonaws.com:5432/stevora?schema=public
REDIS_HOST=your-instance.upstash.io
REDIS_PORT=6379
REDIS_PASSWORD=your-upstash-token
REDIS_DB=0
API_RATE_LIMIT_MAX=500
API_RATE_LIMIT_WINDOW_MS=60000
OPENAI_API_KEY=sk-prod-key
ANTHROPIC_API_KEY=sk-ant-prod-key
ADMIN_TOKEN=your-secure-admin-token
DASHBOARD_URL=https://dashboard.yourdomain.com
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector.yourdomain.com:4318Production (Self-Hosted Everything)
When running PostgreSQL and Redis in Docker alongside Stevora (see Docker Deployment):
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
LOG_LEVEL=info
DATABASE_URL=postgresql://stevora:stevora_secure_pw@postgres:5432/stevora?schema=public
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=stevora_redis_pw
REDIS_DB=0
OPENAI_API_KEY=sk-prod-key
ANTHROPIC_API_KEY=sk-ant-prod-key
ADMIN_TOKEN=your-secure-admin-tokenWhen using Docker Compose, use the service name as the hostname (postgres, redis) instead of localhost. Docker's internal DNS resolves service names to container IP addresses.
Validation
Environment variables are validated at startup using Zod. The validation schema enforces types, formats, and constraints:
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().int().positive().default(3000),
HOST: z.string().default('0.0.0.0'),
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
DATABASE_URL: z.string().url(),
REDIS_HOST: z.string().default('localhost'),
REDIS_PORT: z.coerce.number().int().positive().default(6379),
REDIS_PASSWORD: z.string().optional(),
REDIS_DB: z.coerce.number().int().min(0).default(0),
API_RATE_LIMIT_MAX: z.coerce.number().int().positive().default(100),
API_RATE_LIMIT_WINDOW_MS: z.coerce.number().int().positive().default(60000),
OPENAI_API_KEY: z.string().optional(),
ANTHROPIC_API_KEY: z.string().optional(),
DASHBOARD_URL: z.string().default('http://localhost:3001'),
ADMIN_TOKEN: z.string().optional(),
SENTRY_DSN: z.string().optional(),
OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
});If validation fails, you will see a startup error like this:
Error: Invalid environment variables:
DATABASE_URL: Required
REDIS_PORT: Expected number, received stringFix the reported variables and restart the server.
Next Steps
- Docker Deployment -- Set up the full Docker stack
- API Reference -- Authenticate requests with your API key
- Examples -- Run a real workflow on your deployment