Skip to main content

Overview

Duckling uses environment variables for configuration, loaded from a .env file. Copy .env.example to .env and customize for your deployment.
cp .env.example .env

Server Configuration

NODE_ENV
string
default:"development"
Environment mode
  • development - Enable debugging, hot reload
  • production - Optimized for performance
NODE_ENV=production
PORT
number
default:"3000"
HTTP server portPort for the Express.js server (API + frontend).
PORT=3000
DATA_PATH
string
default:"/app/data"
Base data directoryRoot path for all data storage (databases, backups, metadata).
  • Docker: /app/data (volume mounted from ./data)
  • Development: ./data (relative to project root)
DATA_PATH=/app/data

Database Configuration

DUCKDB_PATH
string
default:"data/duckling.db"
DuckDB database file pathPath to the default DuckDB database file. With multi-database support, individual databases are configured in databases.json.
DUCKDB_PATH=data/duckling.db
DUCKDB_MAX_CONNECTIONS
number
default:"10"
DuckDB connection pool sizeMaximum concurrent connections to DuckDB per database.
DUCKDB_MAX_CONNECTIONS=10
MYSQL_CONNECTION_STRING
string
MySQL source database connection stringConnection string for the source MySQL database to replicate.
MYSQL_CONNECTION_STRING=mysql://user:password@host:port/database?charset=utf8mb4
With multi-database support, each database has its own connection string configured via the /api/databases endpoint. This variable is used for the default database only.
MYSQL_MAX_CONNECTIONS
number
default:"5"
MySQL connection pool sizeMaximum concurrent connections to MySQL per database.
MYSQL_MAX_CONNECTIONS=5
Keep this low to avoid overwhelming the source database. 5-10 connections are typically sufficient.

Sync Configuration

SYNC_INTERVAL_MINUTES
number
default:"15"
Automatic sync frequencyMinutes between automatic incremental sync runs.
SYNC_INTERVAL_MINUTES=15
Set to 0 to disable automatic sync (manual triggers only).
BATCH_SIZE
number
default:"1000"
Records per batch during syncNumber of records to fetch from MySQL in each batch.
BATCH_SIZE=1000
Larger batches are faster but use more memory. 1000-5000 is optimal for most cases.
INSERT_BATCH_SIZE
number
default:"2000"
Insert batch sizeNumber of records to insert per SQL statement during incremental sync.
INSERT_BATCH_SIZE=2000
APPENDER_FLUSH_INTERVAL
number
default:"5000"
Appender flush interval (ms)Milliseconds between automatic flushes of the DuckDB Appender during full sync.
APPENDER_FLUSH_INTERVAL=5000
MAX_RETRIES
number
default:"3"
Retry attempts for failed operationsNumber of times to retry failed sync operations before giving up.
MAX_RETRIES=3
RETRY_BASE_DELAY_MS
number
default:"1000"
Base delay for exponential backoff (ms)Initial delay in milliseconds before first retry. Doubles on each attempt.
RETRY_BASE_DELAY_MS=1000
RETRY_MAX_DELAY_MS
number
default:"60000"
Maximum retry delay (ms)Cap for exponential backoff delay.
RETRY_MAX_DELAY_MS=60000
ENABLE_INCREMENTAL_SYNC
boolean
default:"true"
Enable incremental syncUse watermark-based incremental sync instead of full sync on every run.
ENABLE_INCREMENTAL_SYNC=true
Set to false to force full sync on every run (not recommended for large databases).
EXCLUDED_TABLES
string
Comma-separated list of tables to excludeTables to skip during sync (e.g., temp tables, large logs).
EXCLUDED_TABLES=temp_logs,migration_history,sessions
Leave empty to sync all tables.

Automation Configuration

AUTO_START_SYNC
boolean
default:"true"
Auto-start sync on bootAutomatically start sync service when the server starts.
AUTO_START_SYNC=true
AUTO_CLEANUP
boolean
default:"true"
Enable automatic cleanup tasksRun periodic cleanup tasks (DuckDB VACUUM, WAL cleanup).
AUTO_CLEANUP=true
CLEANUP_INTERVAL_HOURS
number
default:"24"
Hours between cleanup runsFrequency of automatic cleanup tasks.
CLEANUP_INTERVAL_HOURS=24
RETENTION_DAYS
number
default:"90"
Retention period for cleanup (days)Number of days to retain old data before cleanup.
RETENTION_DAYS=90
AUTO_BACKUP
boolean
default:"true"
Enable automatic backupsCreate local backups on a schedule.
AUTO_BACKUP=true
BACKUP_INTERVAL_HOURS
number
default:"24"
Hours between backupsFrequency of automatic backup creation.
BACKUP_INTERVAL_HOURS=24
BACKUP_RETENTION_DAYS
number
default:"7"
Days to retain backupsNumber of days to keep backups before automatic deletion.
BACKUP_RETENTION_DAYS=7
AUTO_RESTART
boolean
default:"true"
Enable auto-restart on failuresAutomatically reconnect to databases on connection failures.
AUTO_RESTART=true
MAX_RESTART_ATTEMPTS
number
default:"3"
Maximum recovery attemptsNumber of times to attempt recovery before giving up.
MAX_RESTART_ATTEMPTS=3
BACKUP_PATH
string
default:"data/backups"
Backup storage directoryDirectory to store local backup files.
BACKUP_PATH=data/backups

Monitoring Configuration

ENABLE_HEALTH_CHECKS
boolean
default:"true"
Enable health check monitoringRun periodic health checks on database connections.
ENABLE_HEALTH_CHECKS=true
HEALTH_CHECK_INTERVAL
number
default:"60000"
Health check interval (ms)Milliseconds between health check runs.
HEALTH_CHECK_INTERVAL=60000
LOG_LEVEL
string
default:"info"
Logging verbosityWinston log level for application logging.
  • error - Errors only
  • warn - Warnings and errors
  • info - General information
  • debug - Detailed debugging
LOG_LEVEL=info

Security & Authentication

ADMIN_USERNAME
string
required
Admin dashboard usernameUsername for web dashboard login.
ADMIN_USERNAME=admin
REQUIRED for production. Change from the default value.
ADMIN_PASSWORD
string
required
Admin dashboard passwordPassword for web dashboard login.
ADMIN_PASSWORD=your-secure-password-here
REQUIRED for production. Use a strong password (16+ characters).
DUCKLING_API_KEY
string
required
API key for programmatic accessBearer token for API authentication.
DUCKLING_API_KEY=your-secure-api-key-here
Generate a secure key:
openssl rand -hex 32
Usage:
curl -H "Authorization: Bearer ${DUCKLING_API_KEY}" \
  http://localhost:3001/api/tables
SESSION_SECRET
string
required
Session encryption secretSecret key for encrypting session cookies.
SESSION_SECRET=generate-with-openssl-rand-hex-32
Generate:
openssl rand -hex 32
REQUIRED for production. Must be a random 64-character hex string.
JWT_SECRET
string
JWT signing secretSecret key for signing JWT tokens. Falls back to SESSION_SECRET if not set.
JWT_SECRET=generate-with-openssl-rand-hex-32
JWT_EXPIRES_IN
string
default:"1h"
JWT expiration timeToken lifetime (e.g., 1h, 7d, 30m).
JWT_EXPIRES_IN=1h

Rate Limiting

RATE_LIMIT_ENABLED
boolean
default:"true"
Enable rate limitingProtect API endpoints from abuse.
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MODE
string
default:"enforce"
Rate limit mode
  • enforce - Block requests exceeding limits
  • shadow - Log violations but allow requests
RATE_LIMIT_MODE=enforce
RATE_LIMIT_USE_SESSION_SCOPE
boolean
default:"false"
Use session-based rate limitingLimit per session instead of per IP address.
RATE_LIMIT_USE_SESSION_SCOPE=false
RATE_LIMIT_INCLUDE_DB_SCOPE
boolean
default:"true"
Include database in rate limit scopeSeparate rate limits per database.
RATE_LIMIT_INCLUDE_DB_SCOPE=true
RATE_LIMIT_READ_MAX
number
default:"120"
Read endpoint limit (requests/minute)Max requests per minute for read operations (GET /tables, /status, etc.).
RATE_LIMIT_READ_MAX=120
RATE_LIMIT_QUERY_MAX
number
default:"80"
Query endpoint limit (requests/minute)Max requests per minute for query operations (POST /query).
RATE_LIMIT_QUERY_MAX=80
RATE_LIMIT_COST_QUERY
number
default:"1"
Cost per query requestWeight of a query request for rate limiting.
RATE_LIMIT_COST_QUERY=1
RATE_LIMIT_COST_WRITE
number
default:"3"
Cost per write requestWeight of a write request (sync, backup) for rate limiting.
RATE_LIMIT_COST_WRITE=3
RATE_LIMIT_JWT_QUERY_MAX_IN_FLIGHT
number
default:"6"
Max concurrent queries (JWT auth)Maximum parallel query executions for JWT-authenticated users.
RATE_LIMIT_JWT_QUERY_MAX_IN_FLIGHT=6
RATE_LIMIT_APIKEY_QUERY_MAX_IN_FLIGHT
number
default:"12"
Max concurrent queries (API key auth)Maximum parallel query executions for API key authentication.
RATE_LIMIT_APIKEY_QUERY_MAX_IN_FLIGHT=12
RATE_LIMIT_QUERY_INFLIGHT_TTL_MS
number
default:"300000"
Query in-flight TTL (ms)Time to keep in-flight query tracking (5 minutes default).
RATE_LIMIT_QUERY_INFLIGHT_TTL_MS=300000

CDC (Change Data Capture)

CDC_ENABLED
boolean
default:"false"
Enable CDC modeUse MySQL binary log replication for real-time sync.
CDC_ENABLED=true
CDC is opt-in. Requires MySQL binary logging to be enabled.
CDC_AUTO_START
boolean
default:"false"
Auto-start CDC on bootAutomatically start CDC service when server starts.
CDC_AUTO_START=true
CDC_RECONNECT_ATTEMPTS
number
default:"10"
CDC reconnection attemptsNumber of times to retry connecting to MySQL binlog.
CDC_RECONNECT_ATTEMPTS=10
CDC_RECONNECT_DELAY_MS
number
default:"5000"
CDC reconnect delay (ms)Milliseconds between reconnection attempts.
CDC_RECONNECT_DELAY_MS=5000
CDC_SSL_REJECT_UNAUTHORIZED
boolean
default:"true"
Verify SSL certificates for CDCReject connections with invalid SSL certificates.
CDC_SSL_REJECT_UNAUTHORIZED=true
CDC_MAX_QUEUE_SIZE
number
default:"5000"
CDC event queue sizeMaximum number of CDC events to buffer before applying backpressure.
CDC_MAX_QUEUE_SIZE=5000

MySQL Protocol Server

MYSQL_PROTOCOL_ENABLED
boolean
default:"true"
Enable MySQL wire protocolAccept connections from MySQL clients.
MYSQL_PROTOCOL_ENABLED=true
MYSQL_PROTOCOL_PORT
number
default:"3307"
MySQL protocol portPort for MySQL wire protocol server.
MYSQL_PROTOCOL_PORT=3307
Connect:
mysql -h localhost -P 3307 -u duckling -p
MYSQL_PROTOCOL_DEFAULT_DB
string
default:"default"
Default database for MySQL connectionsDatabase to use when no database is specified in the connection.
MYSQL_PROTOCOL_DEFAULT_DB=default
MYSQL_PROTOCOL_MAX_CONNECTIONS
number
default:"50"
Max MySQL protocol connectionsMaximum concurrent MySQL client connections.
MYSQL_PROTOCOL_MAX_CONNECTIONS=50
MYSQL_PROTOCOL_USER
string
default:"duckling"
MySQL protocol usernameUsername for MySQL client connections.
MYSQL_PROTOCOL_USER=duckling
MYSQL_PROTOCOL_PASSWORD
string
MySQL protocol passwordPassword for MySQL client connections. Falls back to DUCKLING_API_KEY.
MYSQL_PROTOCOL_PASSWORD=your-password-here

Query Governor

MAX_CONCURRENT_QUERIES
number
default:"10"
Max concurrent queriesMaximum number of queries executing simultaneously.
MAX_CONCURRENT_QUERIES=10
QUERY_TIMEOUT_MS
number
default:"30000"
Query timeout (ms)Maximum execution time for a single query.
QUERY_TIMEOUT_MS=30000
QUERY_QUEUE_MAX
number
default:"50"
Query queue sizeMaximum number of queries to queue when at max concurrency.
QUERY_QUEUE_MAX=50

Worker Threads

WORKER_THREADS
number
default:"0"
Number of worker threadsWorker threads for parallel query execution. 0 = auto (CPU cores - 1, min 1).
WORKER_THREADS=0

Read Replica

READ_REPLICA_ENABLED
boolean
default:"false"
Enable read replica modeRun as a read-only replica of another Duckling instance.
READ_REPLICA_ENABLED=true
REPLICA_REFRESH_INTERVAL
number
default:"300"
Replica refresh interval (seconds)Seconds between syncing from the primary instance.
REPLICA_REFRESH_INTERVAL=300

Error Tracking (Sentry)

SENTRY_DSN
string
Sentry DSNData Source Name for Sentry error tracking.
SENTRY_DSN=https://[email protected]/xxx
SENTRY_RELEASE
string
Sentry release versionRelease identifier for Sentry tracking.
SENTRY_RELEASE=[email protected]
SENTRY_TRACES_SAMPLE_RATE
number
default:"0.1"
Sentry trace sampling ratePercentage of transactions to trace (0.0 to 1.0).
SENTRY_TRACES_SAMPLE_RATE=0.1

CORS

ENABLE_CORS
boolean
default:"true"
Enable CORSAllow cross-origin requests from web browsers.
ENABLE_CORS=true

Example Configuration

Production .env

# Server
NODE_ENV=production
PORT=3000

# Database
DUCKDB_PATH=data/duckling.db
MYSQL_MAX_CONNECTIONS=10

# Sync
SYNC_INTERVAL_MINUTES=15
BATCH_SIZE=5000
ENABLE_INCREMENTAL_SYNC=true

# Automation (all enabled by default)
AUTO_START_SYNC=true
AUTO_BACKUP=true
BACKUP_INTERVAL_HOURS=24
AUTO_RESTART=true

# Monitoring
ENABLE_HEALTH_CHECKS=true
LOG_LEVEL=info

# Security (REQUIRED - change these!)
ADMIN_USERNAME=admin
ADMIN_PASSWORD=$(openssl rand -base64 32)
DUCKLING_API_KEY=$(openssl rand -hex 32)
SESSION_SECRET=$(openssl rand -hex 32)

# Rate Limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MODE=enforce
RATE_LIMIT_READ_MAX=120
RATE_LIMIT_QUERY_MAX=80

Development .env

# Server
NODE_ENV=development
PORT=3000

# Database
DUCKDB_PATH=data/duckling.db
MYSQL_MAX_CONNECTIONS=5

# Sync
SYNC_INTERVAL_MINUTES=5
BATCH_SIZE=1000
ENABLE_INCREMENTAL_SYNC=true

# Monitoring
LOG_LEVEL=debug

# Security (dev values - DO NOT use in production)
ADMIN_USERNAME=admin
ADMIN_PASSWORD=dev123
DUCKLING_API_KEY=dev-api-key
SESSION_SECRET=dev-session-secret

Configuration Validation

The server validates security settings on startup. Check for warnings:
docker logs duckling-server | grep -i "security"
Critical security issues:
  • JWT_SECRET using default value
  • ADMIN_USERNAME or ADMIN_PASSWORD empty
  • SESSION_SECRET not set

Next Steps

Docker Deployment

Deploy with Docker and Docker Compose

Security

Secure your deployment

Production Guide

Production best practices

Build docs developers (and LLMs) love