Local Development Configuration#
Local development mode runs the Dify API (Flask/port 5001), Web (Next.js/port 3000), worker, and Celery Beat directly on the host from source. Docker handles only 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.
Prerequisites: Python 3.12+, uv (replaced poetry as the Python package manager in v1.3.0), pnpm, and Docker.
Quick Start#
The canonical walkthrough is api/README.md. The recommended path uses helper scripts from the repo root:
./dev/setup # Copy env files and install dependencies
./dev/start-docker-compose # Start PostgreSQL / Redis / Weaviate
./dev/start-api # Run DB migrations, then start API on :5001
./dev/start-web # Start Next.js on :3000
./dev/start-worker # Start async/Celery worker
./dev/start-beat # (Optional) Start Celery Beat for scheduled tasks
After ./dev/setup, review the three generated files before starting services: api/.env, web/.env.local, and docker/middleware.env.
Key Environment Variables#
The full reference is api/.env.example (864 lines). Variables that must be set or verified for a working local environment:
| Variable | Local Default | Source |
|---|---|---|
SECRET_KEY | Generate with openssl rand -base64 42 | |
DB_HOST / DB_DATABASE / DB_PASSWORD | localhost / dify / difyai123456 | |
REDIS_HOST / REDIS_PORT / REDIS_PASSWORD | localhost / 6379 / 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_ENDPOINT | weaviate / http://localhost:8080 | |
STORAGE_TYPE / OPENDAL_SCHEME / OPENDAL_FS_ROOT | opendal / fs / storage | |
PLUGIN_DAEMON_KEY | Must match daemon config | |
PLUGIN_DAEMON_URL | http://127.0.0.1:5002 | |
INNER_API_KEY_FOR_PLUGIN | Must match daemon's PLUGIN_DIFY_INNER_API_KEY | |
CODE_EXECUTION_ENDPOINT | http://127.0.0.1:8194 |
COOKIE_DOMAIN: When the frontend and backend run on different subdomains, set this to the shared top-level domain so authentication cookies are shared.
For the frontend, web/.env.local (generated by ./dev/setup) sets NEXT_PUBLIC_API_PREFIX and NEXT_PUBLIC_PUBLIC_API_PREFIX to point at http://localhost:5001.
Service Port Reference#
| Service | Port |
|---|---|
| API (Flask) | 5001 |
| Web (Next.js) | 3000 |
| Plugin Daemon (main) | 5002 |
| Plugin Daemon (debug/remote install) | 5003 |
| Sandbox (code execution) | 8194 |
| Weaviate | 8080 |
| Redis | 6379 |
| PostgreSQL | 5432 |
Plugin Daemon Configuration#
Even in source mode, the plugin daemon runs as a Docker container. Its config template is docker/envs/core-services/plugin-daemon.env.example.
Shared secrets that must match on both sides:
api/.env variable | Daemon 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. The example defaults to http://api:5001 (Docker network DNS), which won't work in source mode β change it to http://host.docker.internal:5001 (Mac/Windows) or the host bridge IP (Linux).
Daemon version must match the Dify API version. A mismatch causes Server disconnected without sending a response errors. After upgrading Dify, 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 silently overrides the first, redirecting traffic to the wrong port.