Local Development Configuration#
Overview#
Local development mode runs the Dify API (Flask), Web (Next.js), worker, and Celery Beat directly on the host from source, while only Docker handles the stateful middleware (PostgreSQL, Redis, Weaviate) and the plugin daemon. This is distinct from the Docker Compose deployment path, where all services run in containers.
The three canonical configuration files are:
api/.env.exampleβ full backend environment reference (794 lines)docker/envs/core-services/plugin-daemon.env.exampleβ plugin daemon configurationapi/README.mdβ authoritative setup walkthrough
Quick Start#
Prerequisites: Python 3.12+, uv, pnpm, Docker. Since v1.3.0, uv replaces poetry as the Python package manager .
# 1. Copy env files and install dependencies
./dev/setup
# 2. Generate SECRET_KEY (Linux)
sed -i "/^SECRET_KEY=/c\\SECRET_KEY=$(openssl rand -base64 42)" api/.env
# 3. Start middleware (PostgreSQL / Redis / Weaviate)
./dev/start-docker-compose
# 4. Start backend API (auto-runs migrations, binds :5001)
./dev/start-api
# 5. Start frontend (binds :3000)
./dev/start-web
# 6. Start async worker
./dev/start-worker
# 7. (Optional) Start Celery Beat for scheduled tasks
./dev/start-beat
See api/README.md for the full annotated walkthrough, including the macOS variant of the SECRET_KEY command and notes on COOKIE_DOMAIN for multi-subdomain setups.
Key Environment Variables#
All variables are documented in api/.env.example. The critical ones to set for a working local environment:
| Variable | Default / Note | Reference |
|---|---|---|
SECRET_KEY | Must be set β use openssl rand -base64 42 | |
DB_HOST / DB_DATABASE / DB_PASSWORD | localhost / dify / difyai123456 | |
REDIS_HOST / REDIS_PASSWORD | localhost / difyai123456 | |
CELERY_BROKER_URL | redis://:difyai123456@localhost:6379/1 | |
CONSOLE_API_URL | http://localhost:5001 | |
CONSOLE_WEB_URL / APP_WEB_URL | http://localhost:3000 | |
VECTOR_STORE | weaviate (default); WEAVIATE_ENDPOINT=http://localhost:8080 | |
STORAGE_TYPE | opendal with OPENDAL_SCHEME=fs, OPENDAL_FS_ROOT=storage | |
PLUGIN_DAEMON_URL | http://127.0.0.1:5002 | |
PLUGIN_DAEMON_KEY | Must match daemon config | |
INNER_API_KEY_FOR_PLUGIN | Must match daemon's PLUGIN_DIFY_INNER_API_KEY | |
CODE_EXECUTION_ENDPOINT | http://127.0.0.1:8194 (sandbox service) |
For frontend, web/.env.local (copied from web/.env.example) sets NEXT_PUBLIC_API_PREFIX and NEXT_PUBLIC_PUBLIC_API_PREFIX to point at the local API.
Service Port Reference#
| Service | Port | Variable |
|---|---|---|
| API (Flask) | 5001 | CONSOLE_API_URL |
| Web (Next.js) | 3000 | CONSOLE_WEB_URL |
| Plugin Daemon (main) | 5002 | PLUGIN_DAEMON_URL |
| Plugin Daemon (debug/remote install) | 5003 | PLUGIN_REMOTE_INSTALL_PORT |
| Sandbox (code execution) | 8194 | CODE_EXECUTION_ENDPOINT |
| Weaviate | 8080 | WEAVIATE_ENDPOINT |
| Redis | 6379 | REDIS_PORT |
| PostgreSQL | 5432 | DB_PORT |
Plugin Daemon Configuration#
Even in source mode, the plugin daemon runs as a Docker container (started via docker-compose.middleware.yaml). Its configuration lives in docker/envs/core-services/plugin-daemon.env.example.
Shared secrets that must match on both sides:
API .env variable | Daemon env variable | Purpose |
|---|---|---|
PLUGIN_DAEMON_KEY | PLUGIN_DAEMON_KEY | APIβDaemon auth |
INNER_API_KEY_FOR_PLUGIN | PLUGIN_DIFY_INNER_API_KEY | DaemonβAPI auth |
PLUGIN_DIFY_INNER_API_URL in the daemon config must reach the host API from inside the container: use http://host.docker.internal:5001 on Mac/Windows or the host bridge IP on Linux. The example defaults to http://api:5001 (Docker network), which must be changed for source mode .
The daemon version must match the Dify API version. A mismatch causes Server disconnected without sending a response errors on the API side. After upgrading Dify, also pull the matching daemon image (e.g., langgenius/dify-plugin-daemon:0.6.1-local for v1.14.x) .
Common pitfall: Duplicate PLUGIN_DAEMON_URL entries in api/.env β the second line silently overrides the first, misdirecting traffic to the wrong port .