Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Dify -- Admin Guide

Generated May 2026 from langgenius/dify at 13a9359

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who deploy, operate, secure, extend, and contribute to Dify. It assumes you have read the User Guide and have a Dify instance running. If you are new to Dify, start there.

Note

Dify is classified as a "massive" complexity project: 11,069 files, 31.7 million source characters, 258 significant modules. This guide covers the full operational surface.


Table of Contents


Executive Summary

Dify is an open-source LLM application development platform that provides a visual workflow builder, RAG pipeline, agent framework, model abstraction layer, and plugin ecosystem. It serves as the full-stack infrastructure for building and deploying AI applications.

Technology Stack

Layer Technology
Backend API Python 3.12+, Flask, Gunicorn + gevent, SQLAlchemy ORM, Pydantic v2
Task Queue Celery with Redis broker
Frontend Next.js 15 (App Router), React 19, Tailwind CSS 4, TypeScript
State Management Zustand, TanStack Query, Jotai
Database PostgreSQL (relational), Redis (cache/queue/pubsub/sessions)
Vector Store 30+ pluggable backends via dify.vector_backends entry points
Plugin Runtime Go-based plugin_daemon, JSON-RPC over stdio
Code Sandbox Isolated execution environment for user code
Reverse Proxy nginx (Docker) or any external proxy
Package Management uv (Python), pnpm 10.33.0 (JavaScript)

Key Metrics (Source: commit 13a9359)

Metric Value
Total files 11,069
Source characters 31.7M
Extracted classes 1,997
Extracted functions 7,321
CLI commands 129
Config keys 59 extracted (200+ total in .env.example)
Vector DB backends 30+
HIGH-priority modules 258

Architecture

System Architecture

                    Internet
                       |
              +--------v--------+
              |     nginx       |  Port 80/443, SSL termination
              |  (reverse proxy)|  Static files, WebSocket upgrade
              +---+--------+---+
                  |        |
        +---------v--+  +--v---------+
        |   web      |  |   api      |  Flask + gevent + WebSocket
        | (Next.js)  |  | :5001      |  4 API surfaces
        | :3000      |  +--+-+--+----+
        +------------+     | |  |
                           | |  +----> plugin_daemon (Go) :5002
                           | |          |-> Plugin processes (stdio JSON-RPC)
                           | |
                    +------+ +------+
                    |               |
              +-----v----+  +------v------+
              |  worker   |  |   sandbox   |  Code execution :8194
              | (Celery)  |  +-------------+
              +--+--+-----+
                 |  |
          +------+  +------+
          |                |
    +-----v------+  +------v-------+
    | PostgreSQL |  |    Redis     |  Cache, broker, sessions,
    |  :5432     |  |   :6379      |  rate limiting, pubsub
    +------------+  +--------------+
          |
    +-----v---------+
    | Vector Store   |  Weaviate :8080 (default)
    | (pluggable)    |  or any of 30+ backends
    +----------------+

Four API Surfaces

Dify exposes four distinct API surfaces, each serving a different audience:

Surface Base Path Auth Purpose
Console API /console/api/* JWT (session) Web UI operations (app CRUD, settings, workspace management)
Service API /v1/* API Key (Bearer) External integrations (chat, completion, workflow execution)
Web API /api/* App token End-user web app interactions
Inner API /inner/api/* INNER_API_KEY_FOR_PLUGIN Plugin daemon communication

Important

The Inner API is exclusively for plugin daemon communication. It is not intended for external use and uses a shared secret key (INNER_API_KEY_FOR_PLUGIN) for authentication.

Process Model

The API server runs Flask under Gunicorn with the gevent worker class, providing cooperative multitasking for handling concurrent requests. The entry point is api/app.py:

# api/app.py
app = create_app()
celery = app.extensions["celery"]

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5001)

In production:

gunicorn --bind 0.0.0.0:5001 \
  --worker-class gevent \
  --workers 1 \
  --timeout 200 \
  app:app

Warning

The gevent worker requires monkey-patching at import time. The app_factory.py handles this. Do not import standard library threading or socket modules before gevent patches are applied.


System Requirements

Hardware Requirements

Deployment Size CPU RAM Disk Notes
Development 2 cores 4 GB 20 GB Minimum viable
Small (< 10 users) 4 cores 8 GB 50 GB Comfortable for teams
Medium (10-100 users) 8 cores 16 GB 100 GB Separate DB recommended
Large (100+ users) 16+ cores 32+ GB 500+ GB Dedicated DB, Redis, VDB

Software Dependencies

Component Required Version Notes
Docker Engine >= 19.03 Docker Compose >= 2.x
Python 3.12+ Managed via uv
Node.js 22.22.1 Strict version (enforced by engines field)
pnpm 10.33.0 Enforced by packageManager field
PostgreSQL 15+ WAL mode, foreign keys enabled
Redis 6+ Used for cache, broker, sessions, pubsub

Installation and Deployment

Docker Compose (Production)

The docker/ directory contains the complete production deployment configuration.

Container Orchestration

Container Image Role Ports
nginx nginx:latest Reverse proxy, static files, SSL 80, 443
web Custom (Next.js) Frontend application 3000 (internal)
api Custom (Flask) Backend API server 5001 (internal)
worker Custom (Celery) Background task processor --
db postgres:15 Relational database 5432 (internal)
redis redis:7 Cache, message broker 6379 (internal)
weaviate semitechnologies/weaviate Default vector store 8080, 50051 (internal)
plugin_daemon Custom (Go) Plugin runtime 5002 (internal)
sandbox Custom Code execution sandbox 8194 (internal)
ssrf_proxy Custom (Squid) Outbound request filtering 3128 (internal)
certbot certbot/certbot SSL certificate automation --

Deployment Steps

cd dify/docker
cp .env.example .env
# Edit .env with your production values
docker compose up -d

# Verify all containers are healthy
docker compose ps
docker compose logs --tail 50 api

nginx Configuration

The bundled nginx config (docker/nginx/) handles:

  • SSL termination (with Certbot-managed Let's Encrypt certificates)
  • WebSocket upgrade for real-time streaming
  • Static file serving for the frontend
  • Proxy pass to api:5001 for API requests
  • Proxy pass to web:3000 for frontend requests

Key nginx directives for Dify:

# Required for SSE streaming
proxy_buffering off;

# Required for WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Source Deployment

Backend Setup

cd api
pip install uv
uv sync --all-extras

# Configure
cp .env.example .env
# Edit .env

# Database initialization
uv run flask upgrade-db

# Start API server
uv run gunicorn --bind 0.0.0.0:5001 \
  --worker-class gevent \
  --workers 1 \
  --timeout 200 \
  app:app

# Start Celery worker (separate terminal)
uv run celery -A app.celery worker \
  -Q dataset,generation,mail,ops_trace \
  --loglevel INFO

Frontend Setup

cd web
pnpm install
pnpm build
pnpm start

Development mode with hot reload:

pnpm dev
# With debugging proxy:
pnpm dev:proxy

Monorepo Structure

The repository is a pnpm monorepo:

dify/
  package.json          # Root workspace config (pnpm 10.33.0, Node 22.22.1)
  web/                  # Main frontend (Next.js 15, version 1.13.3)
  e2e/                  # End-to-end tests (Playwright + Cucumber)
  packages/
    dify-ui/            # Shared UI components (@langgenius/dify-ui)
    iconify-collections/ # Custom icon sets
    tsconfig/           # Shared TypeScript configs
    migrate-no-unchecked-indexed-access/  # TS migration tool
  sdks/
    nodejs-client/      # Node.js SDK (dify-client v3.1.0)
    php-client/         # PHP SDK (Guzzle-based)

SSRF Proxy

The ssrf_proxy container runs Squid configured to block requests to internal/private network ranges. All outbound HTTP requests from workflow HTTP Request nodes and tool calls are routed through this proxy to prevent Server-Side Request Forgery attacks.

Configuration:

SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128
SSRF_DEFAULT_MAX_RETRIES=3
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5

Sandbox (Code Execution)

The sandbox container provides isolated execution for Code nodes in workflows. It runs user-submitted Python and JavaScript in a restricted environment with resource limits.

CODE_EXECUTION_ENDPOINT=http://127.0.0.1:8194
CODE_EXECUTION_API_KEY=dify-sandbox
CODE_MAX_NUMBER=9223372036854775807
CODE_MIN_NUMBER=-9223372036854775808
CODE_MAX_STRING_LENGTH=80000
CODE_MAX_STRING_ARRAY_LENGTH=30
CODE_MAX_OBJECT_ARRAY_LENGTH=30
CODE_MAX_NUMBER_ARRAY_LENGTH=1000
TEMPLATE_TRANSFORM_MAX_LENGTH=80000

The sandbox config lives at docker/volumes/sandbox/conf/.


Configuration Reference

All configuration is via environment variables, defined in .env. The authoritative list is in docker/.env.example. Below is the complete reference organized by category.

Core Application

Variable Default Description
SECRET_KEY -- Flask secret key. Required. Generate with openssl rand -base64 42
DEBUG false Enable Flask debug mode
SQLALCHEMY_ECHO false Echo all SQL queries to log
LOG_LEVEL INFO Logging level (DEBUG, INFO, WARNING, ERROR)
LOG_FILE -- Log file path. Empty = stdout only
LOG_FILE_MAX_SIZE 20 Max log file size in MB
LOG_FILE_BACKUP_COUNT 5 Number of rotated log files to keep
LOG_DATEFORMAT %Y-%m-%d %H:%M:%S Log timestamp format
LOG_TZ UTC Log timezone
LOG_FORMAT %(asctime)s... Python logging format string
INIT_PASSWORD -- Required password for initial /install setup

URLs

Variable Default Description
CONSOLE_API_URL http://127.0.0.1:5001 Console API base URL
CONSOLE_WEB_URL http://127.0.0.1:3000 Console web base URL
SERVICE_API_URL http://127.0.0.1:5001 Service API base URL
APP_WEB_URL http://127.0.0.1:3000 Web app base URL
FILES_URL http://127.0.0.1:5001 File serving base URL
FILES_ACCESS_TIMEOUT 300 File URL signature validity (seconds)

Database (PostgreSQL)

Variable Default Description
DB_USERNAME postgres Database user
DB_PASSWORD difyai123456 Database password
DB_HOST localhost Database host
DB_PORT 5432 Database port
DB_DATABASE dify Database name

Caution

Change DB_PASSWORD and REDIS_PASSWORD from their defaults before exposing Dify to any network. The defaults (difyai123456) are for local development only.

Redis

Variable Default Description
REDIS_HOST localhost Redis host
REDIS_PORT 6379 Redis port
REDIS_USERNAME -- Redis username (ACL)
REDIS_PASSWORD difyai123456 Redis password
REDIS_USE_SSL false Enable TLS for Redis
REDIS_DB 0 Redis database number
REDIS_KEY_PREFIX -- Prefix for all Redis keys
CELERY_BROKER_URL redis://:difyai123456@localhost:6379/1 Celery broker URL

Storage

Variable Default Description
STORAGE_TYPE opendal Storage backend: opendal, s3, aliyun-oss, azure-blob, baidu-obs, google-storage, huawei-obs, oci-storage, tencent-cos, volcengine-tos, supabase
OPENDAL_SCHEME fs OpenDAL scheme (fs, s3, gcs, etc.)
OPENDAL_FS_ROOT storage Local filesystem root for OpenDAL

Vector Store

Variable Default Description
VECTOR_STORE weaviate Vector backend identifier
WEAVIATE_ENDPOINT http://localhost:8080 Weaviate HTTP endpoint
WEAVIATE_API_KEY -- Weaviate API key
WEAVIATE_BATCH_SIZE 100 Weaviate batch operation size
WEAVIATE_TOKENIZATION word Weaviate text tokenization mode
KEYWORD_DATA_SOURCE_TYPE database Keyword search data source

Authentication and Sessions

Variable Default Description
ACCESS_TOKEN_EXPIRE_MINUTES 60 JWT access token lifetime
REFRESH_TOKEN_EXPIRE_DAYS 30 JWT refresh token lifetime
LOGIN_LOCKOUT_DURATION 86400 Account lockout after failed attempts (seconds)
RESET_PASSWORD_TOKEN_EXPIRY_MINUTES 5 Password reset link lifetime
EMAIL_REGISTER_TOKEN_EXPIRY_MINUTES 5 Email registration token lifetime
CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES 5 Email change token lifetime
OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES 5 Ownership transfer token lifetime

CORS

Variable Default Description
WEB_API_CORS_ALLOW_ORIGINS http://127.0.0.1:3000,* Allowed origins for Web API
CONSOLE_CORS_ALLOW_ORIGINS http://127.0.0.1:3000,* Allowed origins for Console API

Mail

Variable Default Description
MAIL_TYPE -- Mail provider: resend or smtp
MAIL_DEFAULT_SEND_FROM no-reply <[email removed]> Default sender address
RESEND_API_KEY -- Resend API key
RESEND_API_URL https://api.resend.com Resend API endpoint
SMTP_SERVER smtp.example.com SMTP server hostname
SMTP_PORT 465 SMTP port
SMTP_USERNAME -- SMTP username
SMTP_PASSWORD -- SMTP password
SMTP_USE_TLS true Enable TLS for SMTP
SMTP_OPPORTUNISTIC_TLS false Opportunistic TLS (STARTTLS)
SMTP_LOCAL_HOSTNAME -- Override local hostname for HELO/EHLO

Notion Integration

Variable Default Description
NOTION_INTEGRATION_TYPE public public (OAuth) or internal (direct token)
NOTION_CLIENT_SECRET -- OAuth client secret
NOTION_CLIENT_ID -- OAuth client ID
NOTION_INTERNAL_SECRET -- Internal integration token

Upload Limits

Variable Default Description
UPLOAD_FILE_SIZE_LIMIT 15 Max file upload size (MB)
UPLOAD_FILE_BATCH_LIMIT 5 Max simultaneous file uploads
UPLOAD_IMAGE_FILE_SIZE_LIMIT 10 Max image upload size (MB)
UPLOAD_VIDEO_FILE_SIZE_LIMIT 100 Max video upload size (MB)
UPLOAD_AUDIO_FILE_SIZE_LIMIT 50 Max audio upload size (MB)
BATCH_UPLOAD_LIMIT 10 Batch upload limit

Workflow Execution

Variable Default Description
WORKFLOW_MAX_EXECUTION_STEPS 500 Max nodes per workflow run
WORKFLOW_MAX_EXECUTION_TIME 1200 Max execution time (seconds)
WORKFLOW_CALL_MAX_DEPTH 5 Max sub-workflow nesting depth
MAX_VARIABLE_SIZE 204800 Max variable size (bytes, 200 KB)
MAX_SUBMIT_COUNT 100 Max parallel thread pool submissions
WORKFLOW_FILE_UPLOAD_LIMIT 10 Max file uploads per workflow run

Application Limits

Variable Default Description
APP_MAX_EXECUTION_TIME 1200 Max app execution time (seconds)
APP_DEFAULT_ACTIVE_REQUESTS 0 Default concurrent request limit (0 = unlimited)
APP_MAX_ACTIVE_REQUESTS 0 Max concurrent request limit (0 = unlimited)
CELERY_BEAT_SCHEDULER_TIME 1 Celery beat polling interval (seconds)

Code Execution (Sandbox)

Variable Default Description
CODE_EXECUTION_ENDPOINT http://127.0.0.1:8194 Sandbox endpoint
CODE_EXECUTION_API_KEY dify-sandbox Sandbox API key
CODE_MAX_NUMBER 9223372036854775807 Max numeric value
CODE_MIN_NUMBER -9223372036854775808 Min numeric value
CODE_MAX_STRING_LENGTH 80000 Max string length
CODE_MAX_STRING_ARRAY_LENGTH 30 Max string array length
CODE_MAX_OBJECT_ARRAY_LENGTH 30 Max object array length
CODE_MAX_NUMBER_ARRAY_LENGTH 1000 Max number array length
TEMPLATE_TRANSFORM_MAX_LENGTH 80000 Max Jinja2 template length

HTTP Request Node

Variable Default Description
HTTP_REQUEST_MAX_CONNECT_TIMEOUT 300 Max connect timeout (seconds)
HTTP_REQUEST_MAX_READ_TIMEOUT 600 Max read timeout (seconds)
HTTP_REQUEST_MAX_WRITE_TIMEOUT 600 Max write timeout (seconds)
HTTP_REQUEST_NODE_MAX_BINARY_SIZE 10485760 Max binary response (10 MB)
HTTP_REQUEST_NODE_MAX_TEXT_SIZE 1048576 Max text response (1 MB)

API Tool

Variable Default Description
API_TOOL_DEFAULT_CONNECT_TIMEOUT 10 Default connect timeout (seconds)
API_TOOL_DEFAULT_READ_TIMEOUT 60 Default read timeout (seconds)

Webhook

Variable Default Description
WEBHOOK_REQUEST_BODY_MAX_SIZE 10485760 Max webhook body size (10 MB)

Plugin System

Variable Default Description
PLUGIN_DAEMON_KEY -- Plugin daemon authentication key
PLUGIN_DAEMON_URL http://127.0.0.1:5002 Plugin daemon endpoint
PLUGIN_REMOTE_INSTALL_PORT 5003 Remote plugin install port
PLUGIN_REMOTE_INSTALL_HOST localhost Remote plugin install host
PLUGIN_MAX_PACKAGE_SIZE 15728640 Max plugin package size (15 MB)
INNER_API_KEY_FOR_PLUGIN -- Shared secret for Inner API auth

Marketplace

Variable Default Description
MARKETPLACE_ENABLED true Enable plugin marketplace
MARKETPLACE_API_URL https://marketplace.dify.ai Marketplace API endpoint

Endpoint Extensions

Variable Default Description
ENDPOINT_URL_TEMPLATE http://localhost:5002/e/{hook_id} Plugin endpoint URL template

SSRF Protection

Variable Default Description
SSRF_PROXY_HTTP_URL -- HTTP proxy for outbound requests
SSRF_PROXY_HTTPS_URL -- HTTPS proxy for outbound requests
SSRF_DEFAULT_MAX_RETRIES 3 Max retries for proxied requests
SSRF_DEFAULT_TIME_OUT 5 Total timeout (seconds)
SSRF_DEFAULT_CONNECT_TIME_OUT 5 Connect timeout (seconds)
SSRF_DEFAULT_READ_TIME_OUT 5 Read timeout (seconds)
SSRF_DEFAULT_WRITE_TIME_OUT 5 Write timeout (seconds)

Model Configuration

Variable Default Description
MULTIMODAL_SEND_FORMAT base64 Image format for multimodal models (base64 or url)
PROMPT_GENERATION_MAX_TOKENS 4096 Max tokens for prompt generation
CODE_GENERATION_MAX_TOKENS 1024 Max tokens for code generation

Indexing

Variable Default Description
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH 4000 Max tokens per chunk
ETL_TYPE dify Document parser: dify or Unstructured
UNSTRUCTURED_API_URL -- Unstructured.io API URL
UNSTRUCTURED_API_KEY -- Unstructured.io API key

Proxy

Variable Default Description
HTTP_PROXY -- HTTP proxy for outbound connections
HTTPS_PROXY -- HTTPS proxy for outbound connections
NO_PROXY localhost,127.0.0.1 Proxy bypass list

Position Configuration

Variable Default Description
POSITION_TOOL_PINS -- Pin tools to top of list
POSITION_TOOL_INCLUDES -- Tool whitelist
POSITION_TOOL_EXCLUDES -- Tool blacklist
POSITION_PROVIDER_PINS -- Pin providers to top
POSITION_PROVIDER_INCLUDES -- Provider whitelist
POSITION_PROVIDER_EXCLUDES -- Provider blacklist

Billing (Enterprise)

Variable Default Description
BILLING_API_URL -- Billing service URL
BILLING_API_SECRET_KEY -- Billing service secret

Sentry

Variable Default Description
SENTRY_DSN -- Sentry DSN for error tracking

Telemetry

Variable Default Description
SCARF_NO_ANALYTICS false Disable anonymous install telemetry

Misc

Variable Default Description
RESPECT_XFORWARD_HEADERS_ENABLED false Trust X-Forwarded-* headers
CREATE_TIDB_SERVICE_JOB_ENABLED false Enable TiDB service job creation

Frontend Environment Variables

All NEXT_PUBLIC_* variables are embedded at build time and available to the client:

Variable Description
NEXT_PUBLIC_API_PREFIX API URL prefix
NEXT_PUBLIC_PUBLIC_API_PREFIX Public API URL prefix
NEXT_PUBLIC_WEB_PREFIX Web app URL prefix
NEXT_PUBLIC_DEPLOY_ENV Deployment environment
NEXT_PUBLIC_EDITION Edition identifier
NEXT_PUBLIC_SOCKET_URL WebSocket URL
NEXT_PUBLIC_SENTRY_DSN Frontend Sentry DSN
NEXT_PUBLIC_ALLOW_EMBED Allow iframe embedding
NEXT_PUBLIC_ALLOW_INLINE_STYLES Allow inline styles in embed
NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME Allow data: URI scheme
NEXT_PUBLIC_BATCH_CONCURRENCY Parallel request limit
NEXT_PUBLIC_COOKIE_DOMAIN Cookie domain scope
NEXT_PUBLIC_CSP_WHITELIST Content Security Policy whitelist
NEXT_PUBLIC_TOP_K_MAX_VALUE Max Top-K retrieval value
NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS Generation timeout (ms)
NEXT_PUBLIC_LOOP_NODE_MAX_COUNT Max loop iterations
NEXT_PUBLIC_MAX_ITERATIONS_NUM Max agent iterations
NEXT_PUBLIC_MAX_TOOLS_NUM Max tools per agent turn
NEXT_PUBLIC_MAX_PARALLEL_LIMIT Max parallel branches
NEXT_PUBLIC_MAX_TREE_DEPTH Max workflow tree depth
NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH Max chunk tokens (UI)
NEXT_PUBLIC_MAINTENANCE_NOTICE Maintenance banner text
NEXT_PUBLIC_IS_MARKETPLACE Marketplace mode flag
NEXT_PUBLIC_MARKETPLACE_API_PREFIX Marketplace API URL
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX Marketplace URL
NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL Enable Firecrawl integration
NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER Enable Jina Reader
NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL Enable WaterCrawl
NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX Enable single-dollar LaTeX
NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON Disable image-as-icon upload
NEXT_PUBLIC_AMPLITUDE_API_KEY Amplitude analytics key
NEXT_PUBLIC_ZENDESK_WIDGET_KEY Zendesk chat widget key

Security

Authentication Architecture

Dify uses JWT-based authentication with access/refresh token pairs:

  1. Login -- User authenticates with email/password or OAuth (Google)
  2. Access Token -- Short-lived JWT (ACCESS_TOKEN_EXPIRE_MINUTES, default 60 min)
  3. Refresh Token -- Long-lived token (REFRESH_TOKEN_EXPIRE_DAYS, default 30 days)
  4. API Keys -- Per-app keys for Service API access (Bearer token)

Brute-Force Protection

Failed login attempts trigger account lockout after repeated failures. The lockout duration is controlled by LOGIN_LOCKOUT_DURATION (default: 86400 seconds / 24 hours).

OAuth Integration

Google OAuth is supported natively. Configure via GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in .env.

Encryption

LLM Credential Storage

LLM API keys and model credentials are encrypted at rest using workspace-specific asymmetric key pairs. Each workspace generates a unique key pair on creation.

Caution

Running flask reset-encrypt-key-pair regenerates the workspace encryption keys. All stored LLM credentials become invalid and must be re-entered. Only use this command when the key pair is compromised.

Secret Key

The SECRET_KEY is used for:

  • Flask session signing
  • JWT token signing
  • CSRF protection

Generate a strong key: openssl rand -base64 42

API Key Security

  • Service API keys are scoped to individual apps
  • Keys are hashed before storage; the plaintext is shown only once on creation
  • Rotate keys regularly; old keys can be revoked from the app settings

SSRF Protection

The ssrf_proxy container blocks outbound requests to private network ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, etc.) to prevent Server-Side Request Forgery attacks from user-controlled workflow nodes.

Content Security

Code Sandbox Isolation

User-submitted code in workflow Code nodes runs in the sandbox container with:

  • Process isolation from the main application
  • Resource limits (CPU, memory, execution time)
  • No network access (unless explicitly configured)
  • No filesystem access outside the sandbox

Content Moderation

Three layers of content moderation are available:

  1. OpenAI Moderation API -- Automated content classification
  2. Custom Keywords -- Regex/exact-match blocklist
  3. External API -- Custom moderation endpoint

File Access Control

Files are served with signed URLs that expire after FILES_ACCESS_TIMEOUT seconds (default: 300). The signature prevents unauthorized access to uploaded files.

CORS Configuration

Restrict allowed origins in production:

WEB_API_CORS_ALLOW_ORIGINS=https://your-domain.com
CONSOLE_CORS_ALLOW_ORIGINS=https://your-domain.com

Warning

Never use * for CORS origins in production. This allows any website to make API requests on behalf of authenticated users.

X-Forwarded Headers

Set RESPECT_XFORWARD_HEADERS_ENABLED=true only when Dify is behind a trusted reverse proxy. This tells Flask to trust X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host headers for correct URL generation and client IP detection.


Operations

Health Checks

Endpoint Purpose
GET /health Full health check (DB, Redis connectivity)
GET /ping Simple liveness probe
GET /db-pool-stat SQLAlchemy connection pool statistics
GET /threads Active thread count

Backup and Restore

PostgreSQL

# Backup
docker compose exec db pg_dump -U postgres dify > dify_backup_$(date +%Y%m%d).sql

# Restore
docker compose exec -T db psql -U postgres dify < dify_backup_20260513.sql

Redis

Redis data is ephemeral (cache, sessions) and does not require routine backup. For persistence, configure Redis RDB/AOF snapshots in redis.conf.

File Storage

Back up the storage directory based on your STORAGE_TYPE:

  • opendal (fs): Back up the directory at OPENDAL_FS_ROOT
  • S3/cloud: Rely on provider's backup mechanisms

Complete Backup Checklist

  1. PostgreSQL dump
  2. .env file
  3. Storage directory (uploads, keys)
  4. nginx configuration (if customized)
  5. Plugin data (if using custom plugins)

Scaling

Horizontal Scaling

  • API servers: Run multiple api containers behind a load balancer. Ensure all share the same SECRET_KEY, database, and Redis.
  • Celery workers: Add worker containers with --concurrency flag. All workers share the same Redis broker.
  • Frontend: The web container is stateless; scale freely.

Vertical Scaling

  • Database: Increase PostgreSQL shared_buffers, work_mem, max_connections
  • Redis: Increase maxmemory; configure eviction policy (allkeys-lru recommended)
  • Vector store: Scale according to your backend's documentation

Queue Scaling

Celery queues and their purposes:

  • dataset -- Document processing, embedding, indexing
  • generation -- LLM generation tasks
  • mail -- Email delivery
  • ops_trace -- Operational tracing/logging

Scale selectively:

# Dedicated worker for dataset processing
celery -A app.celery worker -Q dataset --concurrency 4

# Dedicated worker for generation
celery -A app.celery worker -Q generation --concurrency 2

Log Management

API Logs

# View recent API logs
docker compose logs --tail 200 api

# Follow logs in real time
docker compose logs -f api

# Filter by level
docker compose logs api 2>&1 | grep ERROR

Log Configuration

LOG_LEVEL=INFO
LOG_FILE=/var/log/dify/api.log
LOG_FILE_MAX_SIZE=20
LOG_FILE_BACKUP_COUNT=5
LOG_TZ=UTC

Aliyun SLS Integration

For cloud-based log management:

ALIYUN_SLS_ENDPOINT=<endpoint>
ALIYUN_SLS_REGION=<region>
ALIYUN_SLS_PROJECT_NAME=<project>
ALIYUN_SLS_CHECK_CONNECTIVITY_TIMEOUT=30

Database Migrations

Migrations use Flask-Migrate (Alembic). They run automatically on API container startup.

# Run migrations manually
docker compose exec api flask upgrade-db

# Check current migration version
docker compose exec api flask db current

Storage Migration

Migrate files between storage backends:

docker compose exec api flask migrate-oss \
  --source opendal \
  --path upload_files \
  --path image_files \
  --dry-run

# Execute the migration
docker compose exec api flask migrate-oss \
  --source opendal \
  --update-db

Supported paths: privkeys, upload_files, image_files, tools, website_files, keyword_files, ops_trace.

Data Retention

Workflow Runs

# Preview cleanup (dry run)
docker compose exec api flask clean-workflow-runs \
  --before-days 30 --dry-run

# Execute cleanup
docker compose exec api flask clean-workflow-runs \
  --before-days 30 --batch-size 200

# Archive to S3 before deleting
docker compose exec api flask archive-workflow-runs \
  --before-days 90 --delete-after-archive --workers 4

# Restore from archive
docker compose exec api flask restore-workflow-runs \
  --tenant-ids "tenant-uuid" --run-id "run-uuid"

Messages

docker compose exec api flask clean-expired-messages \
  --before-days 90 --graceful-period 21 --dry-run

The --graceful-period adds extra days after subscription expiration before cleanup.

Export Data

docker compose exec api flask export-app-messages \
  --app-id "app-uuid" \
  --end-before "2026-01-01" \
  --filename "export/messages" \
  --batch-size 1000

# Upload directly to cloud storage
docker compose exec api flask export-app-messages \
  --app-id "app-uuid" \
  --end-before "2026-01-01" \
  --use-cloud-storage

Orphaned Resources

# Find orphaned file records (DB records without storage files)
docker compose exec api flask clear-orphaned-file-records --force

# Find orphaned storage files (storage files without DB records)
docker compose exec api flask remove-orphaned-files-on-storage --force

# Query file usage
docker compose exec api flask file-usage --file-id "uuid" --json

Draft Variables

docker compose exec api flask cleanup_orphaned_draft_variables \
  --dry-run --batch-size 1000 --max-apps 100

Workflow Engine Internals

Graph Execution Model

The workflow engine uses a DAG-based graph executor built on the graphon package. Key concepts:

  1. Graph Definition -- Nodes and edges defined in the workflow DSL (JSON/YAML)
  2. Topological Execution -- Nodes execute in dependency order
  3. Parallel Branches -- Independent branches run concurrently via a ThreadPoolExecutor (max MAX_SUBMIT_COUNT = 100 threads)
  4. Variable Aggregation -- Variable Aggregator nodes act as join points, waiting for all upstream branches

Execution Lifecycle

Start Node
  -> Resolve dependencies
  -> Execute node
    -> If parallel paths: submit to thread pool
    -> If conditional: evaluate IF/ELSE
    -> If iteration: loop over items
    -> If sub-workflow: recursive execution (depth <= WORKFLOW_CALL_MAX_DEPTH)
  -> Collect outputs
  -> Route to next node(s)
  -> ... repeat ...
End Node
  -> Assemble final outputs
  -> Persist workflow_run record

Node Execution Details

Each node type has a specific executor:

  • LLM Node -- Assembles prompt from template + variables, calls model, streams response
  • Knowledge Retrieval Node -- Queries vector store, optionally re-ranks, returns chunks
  • Code Node -- Sends code to sandbox via HTTP, receives output
  • HTTP Request Node -- Makes HTTP call through SSRF proxy, parses response
  • Sub-Workflow Node -- Creates a child workflow run, shares trace_id for observability

Human-in-the-Loop

Workflows support human input nodes that pause execution and wait for user approval/input. The resume mechanism:

  1. Workflow reaches human input node
  2. Execution state is persisted to PostgreSQL
  3. API returns a task_id for the paused run
  4. User submits input via API
  5. Workflow resumes from the paused node

Draft/Preview Mode

Single-node execution for debugging:

  • Creates its own trace_id derived from node_execution_id
  • Does not create a workflow run record
  • Useful for testing LLM prompts, code, and HTTP requests in isolation

RAG Pipeline Internals

Document Processing Pipeline

Upload -> Extractor -> Cleaner -> Chunker -> Embedder -> Vector Store

Extractors

Format Extractor Notes
PDF Built-in or Unstructured.io ETL_TYPE controls which
DOCX python-docx
TXT/MD Direct read
HTML BeautifulSoup Strips tags, preserves structure
CSV/XLSX pandas Row-per-chunk option
EPUB epub parser

Chunking Strategies

  1. Automatic -- Heuristic-based splitting by paragraphs and sections
  2. Custom -- User-defined separator (e.g., \n\n) + max chunk size + overlap
  3. Parent-Child -- Hierarchical chunking for context preservation

Key parameter: INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH (default: 4000) sets the maximum tokens per chunk.

Embedding Pipeline

  1. Text chunks are batched and sent to the configured embedding model
  2. Vectors are stored in the configured vector backend
  3. Full-text indexes are maintained in parallel (for keyword/hybrid search)
  4. The dataset Celery queue handles all processing asynchronously

Retrieval Pipeline

Query -> Query Embedding -> Vector Search (Top-K)
              |
              +-> Full-Text Search (BM25)
              |
              +-> Hybrid (merge + deduplicate)
                    |
                    +-> Reranker (optional)
                          |
                          +-> Score Threshold Filter
                                |
                                +-> Context Assembly -> LLM

Vector Store Registration System

Vector backends are registered via Python entry points under the dify.vector_backends group. The discovery mechanism:

  1. Backend packages live in api/providers/vdb/<backend>/
  2. Each has a pyproject.toml with entry point registration
  3. vector_backend_registry.py lazily loads and caches factory classes
  4. At runtime, get_vector_factory_class(vector_type) resolves the backend

See Vector Database Backend System for details.


Plugin System Internals

Architecture

Flask API
  |
  v
Inner API (/inner/api/*)
  |  (INNER_API_KEY_FOR_PLUGIN auth)
  v
plugin_daemon (Go binary, :5002)
  |
  +-> Plugin Process 1 (stdio JSON-RPC)
  +-> Plugin Process 2 (stdio JSON-RPC)
  +-> ...

Plugin Types

Type Purpose Registration
Model Provider Add LLM/embedding/reranker backends Appears in Model Providers settings
Tool Callable actions for agents/workflows Appears in Tools panel
Extension Custom endpoints, triggers Endpoint-based

Plugin Package Format

Plugins are distributed as .difypkg files containing:

  • Manifest (plugin metadata, version, dependencies)
  • Implementation code
  • Configuration schema

Plugin Communication

The plugin_daemon manages plugin lifecycle:

  1. Plugin installation (download, extract, validate)
  2. Plugin startup (spawn process, establish stdio JSON-RPC channel)
  3. Request routing (API -> Inner API -> daemon -> plugin process)
  4. Plugin shutdown and cleanup

Plugin CLI Commands

# Migrate existing data for plugin system
flask migrate-data-for-plugin

# Extract plugin definitions from existing configuration
flask extract-plugins --output_file plugins.jsonl --workers 10

# Bulk install plugins
flask install-plugins --input_file plugins.jsonl --output_file installed_plugins.jsonl --workers 100

# Install RAG pipeline plugins
flask install-rag-pipeline-plugins --workers 100

# Configure OAuth for tool plugins
flask setup-system-tool-oauth-client --provider github --client-params '{"client_id":"...","client_secret":"..."}'

# Configure OAuth for trigger plugins
flask setup-system-trigger-oauth-client --provider github --client-params '...'

# Configure OAuth for datasource plugins
flask setup-datasource-oauth-client --provider notion --client-params '...'

# Transform datasource credentials
flask transform-datasource-credentials --environment online

Vector Database Backend System

Architecture

The vector store system uses a plugin architecture based on Python entry points:

api/core/rag/datasource/vdb/
  vector_factory.py         # Main entry: Vector class
  vector_backend_registry.py # Entry point discovery + caching
  abstract_vector_factory.py # AbstractVectorFactory interface
  base_vector.py            # BaseVector interface

api/providers/vdb/
  <backend>/
    pyproject.toml          # Package + entry point registration
    src/dify_vdb_<backend>/
      <backend>_vector.py   # Implementation

Interfaces

Interface Methods Purpose
AbstractVectorFactory init_vector(dataset, attributes, embeddings) Create a BaseVector instance
BaseVector create, add_texts, search_by_vector, delete, delete_by_ids Vector operations

Complete Backend List

Backend Entry Point Package Key Dependency
Weaviate weaviate dify-vdb-weaviate weaviate-client==4.20.5
Qdrant qdrant dify-vdb-qdrant qdrant-client==1.9.0
pgvector pgvector dify-vdb-pgvector pgvector==0.4.2
pgvecto-rs pgvecto-rs dify-vdb-pgvecto-rs pgvecto-rs[sqlalchemy]~=0.2.2
Milvus milvus dify-vdb-milvus pymilvus~=2.6.12
Chroma chroma dify-vdb-chroma chromadb==0.5.20
Elasticsearch elasticsearch dify-vdb-elasticsearch elasticsearch==8.14.0
Elasticsearch (JP) elasticsearch-ja dify-vdb-elasticsearch elasticsearch==8.14.0
OpenSearch opensearch dify-vdb-opensearch opensearch-py==3.1.0
TiDB Vector tidb_vector dify-vdb-tidb-vector tidb-vector==0.0.15
TiDB on Qdrant tidb_on_qdrant dify-vdb-tidb-on-qdrant qdrant-client==1.9.0
Oracle oracle dify-vdb-oracle oracledb==3.4.2
OceanBase oceanbase dify-vdb-oceanbase pyobvector~=0.2.17
SeekDB seekdb dify-vdb-oceanbase pyobvector~=0.2.17
Couchbase couchbase dify-vdb-couchbase couchbase~=4.6.0
Tencent tencent dify-vdb-tencent tcvectordb~=2.1.0
Baidu baidu dify-vdb-baidu pymochow==2.4.0
Hologres hologres dify-vdb-hologres holo-search-sdk>=0.4.2
AnalyticDB analyticdb dify-vdb-analyticdb alibabacloud_gpdb20160503~=5.2.0
Alibaba Cloud MySQL alibabacloud_mysql dify-vdb-alibabacloud-mysql mysql-connector-python>=9.3.0
Lindorm lindorm dify-vdb-lindorm opensearch-py==3.1.0
Upstash upstash dify-vdb-upstash upstash-vector==0.8.0
VikingDB vikingdb dify-vdb-vikingdb volcengine-compat~=1.0.0
MyScale myscale dify-vdb-myscale clickhouse-connect~=0.15.0
Tablestore tablestore dify-vdb-tablestore tablestore==6.4.4
Huawei Cloud huawei_cloud dify-vdb-huawei-cloud elasticsearch==8.14.0
IRIS iris dify-vdb-iris intersystems-irispython>=5.1.0
MatrixOne matrixone dify-vdb-matrixone mo-vector~=0.1.13
Clickzetta clickzetta dify-vdb-clickzetta clickzetta-connector-python>=0.8.102
Relyt relyt dify-vdb-relyt --
OpenGauss opengauss dify-vdb-opengauss --
Vastbase vastbase dify-vdb-vastbase pyobvector~=0.2.17

Adding a New Backend

  1. Create api/providers/vdb/<your_backend>/
  2. Add pyproject.toml:
    [project]
    name = "dify-vdb-your-backend"
    version = "0.0.1"
    dependencies = ["your-client-lib>=1.0"]
    
    [project.entry-points."dify.vector_backends"]
    your_backend = "dify_vdb_your_backend.your_backend_vector:YourBackendFactory"
    
    [tool.setuptools.packages.find]
    where = ["src"]
    
  3. Implement AbstractVectorFactory and BaseVector
  4. Add to api/pyproject.toml:
    • [tool.uv.sources]: dify-vdb-your-backend = { workspace = true }
    • [project.optional-dependencies]: add to vdb-all group
  5. Run uv sync in api/

Vector Migration

flask vdb-migrate --scope all

Migrates all datasets from the current vector backend to the one configured in VECTOR_STORE.


Frontend Architecture

Technology Stack

Technology Version Purpose
Next.js 15 App Router framework
React 19 UI library
TypeScript Latest Type safety
Tailwind CSS 4 Utility-first styling
Zustand Latest Client state management
TanStack Query Latest Server state management
Jotai Latest Atomic state management
ReactFlow Latest Workflow canvas
socket.io-client Latest Real-time WebSocket communication
i18next Latest Internationalization (20+ languages)

Project Structure

web/
  app/                    # Next.js App Router pages
    (commonLayout)/       # Authenticated layout group
      datasets/           # Knowledge base UI
      apps/               # Application management
    signin/               # Authentication pages
    components/           # Shared components
      workflow/           # Workflow editor (ReactFlow)
      datasets/           # Dataset management
      plugins/            # Plugin management
      billing/            # Billing (enterprise)
  config/                 # App configuration
  hooks/                  # Custom React hooks (26 files)
  service/                # API service layer (55 files)
  models/                 # TypeScript type definitions (10 files)
  utils/                  # Utility functions (52 files)
  i18n/                   # Translations (20+ locales)
  i18n-config/            # i18n configuration
  contract/               # API contracts / types
  constants/              # App constants
  public/                 # Static assets
    vs/                   # Monaco editor (bundled)
  docker/                 # Frontend Dockerfile

Build and Development

# Development
pnpm dev                  # Next.js dev server
pnpm dev:proxy            # Dev with Hono proxy
pnpm dev:vinext           # Vite-based dev (experimental)

# Build
pnpm build                # Next.js production build
pnpm build:vinext         # Vite-based build (experimental)

# Quality
pnpm type-check           # TypeScript checking
pnpm lint                 # ESLint
pnpm test                 # Vitest tests
pnpm test:coverage        # Test coverage
pnpm storybook            # Component development

# Utilities
pnpm gen-icons            # Regenerate icon components
pnpm i18n:check           # Validate translations
pnpm knip                 # Find unused code
pnpm analyze              # Bundle analysis

Internationalization

Translations live in web/i18n/<locale>/ (30 files per locale). Supported locales: en-US, zh-Hans, zh-Hant, ja-JP, ko-KR, de-DE, fr-FR, it-IT, es-ES, pt-BR, ru-RU, tr-TR, vi-VN, th-TH, ar-TN, hi-IN, pl-PL, ro-RO, sl-SI, uk-UA, fa-IR.


Backend Architecture

Module Organization

api/
  app.py                  # Entry point (Flask + gevent WebSocket)
  app_factory.py          # Flask app factory (gevent monkey-patch)
  commands/               # Flask CLI commands (7 files, 129 commands)
    account.py            # reset-password, reset-email, create-tenant
    plugin.py             # Plugin migration and OAuth setup
    retention.py          # Data cleanup and archival
    storage.py            # File management and migration
    system.py             # DB upgrades, encryption, app conversion
    vector.py             # Vector DB migration
  configs/                # Pydantic v2 configuration
    middleware/            # Redis, PostgreSQL, storage, etc.
  constants/              # Application constants (6 files, 350KB)
  context/                # Request context management (4 files)
  controllers/            # API route handlers
    console/              # Console API (16 files + app/ 25 files + auth/ 9 files)
    service_api/          # Service API (3 files + app/ 11 files)
    web/                  # Web API (19 files)
    inner_api/            # Inner API (app/ 2 files + plugin/ 2 files)
    common/               # Shared controller utilities (6 files)
  core/                   # Core business logic
    app/apps/             # Application runtime (pipeline, common)
    moderation/           # Content moderation
    external_data_tool/   # External data integration
    tools/                # Tool system (12 util files)
    trigger/              # Trigger system
    plugin/               # Plugin integration (3 util files)
    rag/datasource/vdb/   # Vector store interfaces
    prompt/               # Prompt utilities (4 files)
    schemas/              # Core schemas (4 files)
    errors/               # Error definitions
    datasource/           # Data source utilities
  enums/                  # Enum definitions (3 files)
  extensions/             # Flask extensions
    otel/                 # OpenTelemetry integration
    ext_logstore.py       # Aliyun SLS log integration
  fields/                 # API response field definitions (26 files)
  libs/                   # Utility libraries (35 files)
  migrations/             # Alembic database migrations
  models/                 # SQLAlchemy ORM models (22 files, 395KB)
  repositories/           # Data access layer (11 files)
  schedule/               # Celery beat scheduled tasks (13 files)
  services/               # Business logic services (57 files, 1MB)
    auth/                 # Authentication services (5 files)
    plugin/               # Plugin services (9 files)
  providers/vdb/          # Vector database backends (30+ packages)

Key Modules by Size

Module Files Size Purpose
api/services 57 1 MB Core business logic services
api/models 22 395 KB SQLAlchemy ORM models
api/constants 6 350 KB Application constants
api/controllers/console/app 25 329 KB Console API handlers
api/libs 35 156 KB Utility libraries
api/commands 7 123 KB CLI commands
api/repositories 11 124 KB Data access layer
api/controllers/web 19 110 KB Web API handlers
api/controllers/console 16 92 KB Console API (non-app)
api/controllers/service_api/app 11 81 KB Service API handlers
api/fields 26 80 KB Response field definitions

Configuration System

Dify uses Pydantic v2 settings classes for configuration (api/configs/). The middleware config (api/configs/middleware/) defines typed settings for:

  • PostgreSQL connection
  • Redis connection
  • Storage backends
  • Vector store selection
  • Celery configuration

All settings are loaded from environment variables at startup.

Error Handling

The codebase defines specific error classes for different domains:

  • Auth errors: ApiKeyAuthFailedError, InvalidEmailError, PasswordMismatchError, AccountLoginError, UnauthorizedError
  • Dataset errors: NoFileUploadedError, UnsupportedFileTypeError, FileTooLargeError, TooManyFilesError
  • Workspace errors: WorkspaceMemberNotFoundError, WorkspaceQuotaExhaustedError

Errors are caught by Flask error handlers and returned as structured JSON responses.


Database Schema and Migrations

ORM Layer

Dify uses SQLAlchemy ORM with 22 model files defining the complete schema. Key models include:

  • Account -- User accounts, credentials, OAuth tokens
  • Tenant -- Workspaces, member relationships, roles
  • App -- Application definitions, configurations, DSL
  • Conversation -- Chat conversations, message history
  • Message -- Individual messages with metadata
  • Dataset -- Knowledge base definitions
  • Document -- Documents within datasets
  • DocumentSegment -- Chunks/segments with embeddings
  • WorkflowRun -- Workflow execution records
  • WorkflowNodeExecution -- Per-node execution records
  • InstalledPlugin -- Plugin installation records
  • ApiToken -- API key records (hashed)
  • UploadFile -- File upload metadata

Migration Management

Migrations use Flask-Migrate (Alembic wrapper):

# Run pending migrations
flask upgrade-db

# Check current version
flask db current

# Generate new migration (development)
flask db migrate -m "description"

Migrations run automatically on API container startup. The database uses WAL mode with foreign keys enabled.


Celery Task System

Queue Architecture

Queue Tasks Purpose
dataset Document processing, embedding, indexing Knowledge base operations
generation LLM inference, streaming responses Model interactions
mail Email delivery (password reset, invitations) Notifications
ops_trace Operational tracing, analytics Observability

Scheduled Tasks

Celery Beat runs scheduled tasks defined in api/schedule/ (13 files). The beat polling interval is CELERY_BEAT_SCHEDULER_TIME (default: 1 second).

Worker Configuration

# Single worker, all queues
celery -A app.celery worker -Q dataset,generation,mail,ops_trace --loglevel INFO

# Dedicated workers per queue
celery -A app.celery worker -Q dataset --concurrency 4 --loglevel INFO
celery -A app.celery worker -Q generation --concurrency 2 --loglevel INFO

Broker Configuration

Redis is the default and only supported broker:

CELERY_BROKER_URL=redis://:password@redis:6379/1

The broker uses Redis DB 1 (separate from the main cache on DB 0).


Observability and Telemetry

Enterprise Telemetry (OTEL)

Dify Enterprise supports OpenTelemetry integration with a "slim span + rich companion log" architecture:

Signal Purpose Completeness
Traces (Spans) Structure, identity, timing of operations Per-workflow, per-node
Structured Logs Deep context (inputs, outputs, metadata) Correlated via trace_id + span_id
Metrics Counters and histograms 100% accurate (no sampling)

Configuration

Variable Default Description
ENTERPRISE_ENABLED false Master switch for enterprise features
ENTERPRISE_TELEMETRY_ENABLED false Master switch for telemetry
ENTERPRISE_OTLP_ENDPOINT -- OTLP collector endpoint
ENTERPRISE_OTLP_HEADERS -- Custom OTLP headers
ENTERPRISE_OTLP_PROTOCOL http Transport protocol (http or grpc)
ENTERPRISE_OTLP_API_KEY -- Bearer token for auth
ENTERPRISE_INCLUDE_CONTENT false Include sensitive I/O in logs
ENTERPRISE_SERVICE_NAME dify Service name in OTEL
ENTERPRISE_OTEL_SAMPLING_RATE 1.0 Trace sampling rate (0.0-1.0)

Trace ID Correlation

  • Workflow runs: trace_id = UUID(workflow_run_id)
  • Node executions: span_id = hash(node_execution_id), child of workflow span
  • Sub-workflows: Shares parent's trace_id, linked via parent_span_id
  • Draft executions: Own trace_id = UUID(node_execution_id) (not part of any workflow trace)

Content Gating

When ENTERPRISE_INCLUDE_CONTENT=false, sensitive content is replaced with reference strings:

ref:workflow_run_id=550e8400-e29b-41d4-a716-446655440000
ref:node_execution_id=660e8400-e29b-41d4-a716-446655440001

Sentry Integration

Set SENTRY_DSN for backend error tracking and NEXT_PUBLIC_SENTRY_DSN for frontend.

Amplitude Analytics

Set NEXT_PUBLIC_AMPLITUDE_API_KEY for frontend user analytics.


Code Patterns and Conventions

Backend Patterns

Pattern Usage
Pydantic v2 validation Request/response models use Pydantic v2 for validation and serialization
SQLAlchemy ORM All database access through ORM models, never raw SQL
Flask-RESTful API routes use Flask-RESTful resource classes
Celery tasks Long-running operations dispatched to background queues
Entry points Plugin discovery via importlib.metadata.entry_points
gevent Cooperative multitasking for concurrent request handling
Click All CLI commands use the Click framework
Config-as-code Pydantic settings classes with environment variable loading

Frontend Patterns

Pattern Usage
App Router Next.js 15 App Router with route groups (commonLayout)
Zustand Client-side state management (UI state)
TanStack Query Server state management (API data)
Jotai Atomic state for fine-grained reactivity
ReactFlow Workflow canvas with custom node components
i18next Internationalization with server/client split
Tailwind CSS 4 Utility-first styling with @langgenius/dify-ui preset
Zod Runtime schema validation

API Response Format

API responses follow a consistent structure:

{
  "result": "success",
  "data": { ... }
}

Error responses:

{
  "code": "error_code",
  "message": "Human-readable description",
  "status": 400
}

Testing

# Backend unit tests
cd api
uv run pytest tests/unit_tests/

# Backend integration tests
uv run pytest tests/integration_tests/

# Specific test
uv run pytest tests/unit_tests/core/workflow/graph_engine/layers/test_llm_quota.py

# Frontend tests
cd web
pnpm test
pnpm test:coverage

SDKs and Client Libraries

Node.js SDK (dify-client v3.1.0)

Class Purpose
DifyClient Base client with HTTP methods
ChatClient Chat/Agent-Chat interactions
CompletionClient Completion requests
WorkflowClient Workflow execution
KnowledgeBaseClient Dataset management
npm install dify-client

Requires Node.js >= 18.0.0. ESM-only ("type": "module").

PHP SDK

Based on Guzzle HTTP client v7.9. Requires PHP >= 7.2.

composer require langgenius/dify-client

Python SDK

Maintained in a separate repository: github.com/langgenius/dify-sdk-python.


E2E Testing

Framework

End-to-end tests use Playwright + Cucumber (BDD):

cd e2e
pnpm e2e:install        # Install Playwright + Chromium
pnpm e2e:middleware:up   # Start test infrastructure
pnpm e2e                 # Run tests
pnpm e2e:full            # Full test suite
pnpm e2e:full:headed     # Full suite with browser UI
pnpm e2e:reset           # Reset test state
pnpm e2e:middleware:down # Stop test infrastructure

Tests are in e2e/features/ with step definitions in e2e/features/step-definitions/.


Contributing

Development Setup

  1. Fork and clone the repository
  2. Set up the backend and frontend as described in Source Deployment
  3. Create a feature branch

Code Quality Tools

# Linting (root)
pnpm lint
pnpm lint:fix

# Type checking (frontend)
cd web && pnpm type-check

# Backend tests
cd api && uv run pytest

# Frontend tests
cd web && pnpm test

Commit and PR Guidelines

  • PRs should target the main branch
  • Include tests for new features
  • Follow existing code patterns and naming conventions
  • Update translations for UI-facing changes

Known Issues and Improvements

Open Issues (from GitHub)

Key bugs and feature requests from the issue tracker:

  • Performance: Workflow execution with many parallel branches can hit thread pool limits (MAX_SUBMIT_COUNT)
  • Vector Migration: vdb-migrate requires downtime; no online migration path
  • Plugin Isolation: Plugin crashes can affect the daemon's ability to route to other plugins
  • Large File Processing: Documents near the UPLOAD_FILE_SIZE_LIMIT can cause worker memory spikes during extraction

Architecture Improvement Opportunities

  1. API server decomposition -- api/controllers/console/app/ (25 files, 329 KB) handles too many concerns; could benefit from further route grouping
  2. Service layer complexity -- api/services/ (57 files, 1 MB) is the largest module; some services could be broken into domain-specific sub-modules
  3. Workflow engine hardening -- The graph engine delegates to graphon but the Dify layer adds complexity with human-input resume and sub-workflow recursion
  4. Frontend bundle size -- The bundled Monaco editor (web/public/vs/, 377 KB compressed) loads on all pages; could be lazy-loaded
  5. Test coverage -- Integration tests exist but are concentrated in api/tests/test_containers_integration_tests/services (65 files, 1.7 MB); unit test coverage for controllers is lighter

CLI Reference

All CLI commands are invoked via Flask. In Docker: docker compose exec api flask <command>.

Account Commands (api/commands/account.py)

reset-password

Reset an account's password.

flask reset-password \
  --email [email removed] \
  --new-password "SecurePassword123" \
  --password-confirm "SecurePassword123"

reset-email

Change an account's email address.

flask reset-email \
  --email [email removed] \
  --new-email [email removed] \
  --email-confirm [email removed]

create-tenant

Create a new workspace and account.

flask create-tenant \
  --email [email removed] \
  --name "My Workspace" \
  --language en-US

Plugin Commands (api/commands/plugin.py)

setup-system-tool-oauth-client

Configure OAuth for a tool plugin provider.

flask setup-system-tool-oauth-client \
  --provider github \
  --client-params '{"client_id":"...","client_secret":"..."}'

setup-system-trigger-oauth-client

Configure OAuth for a trigger plugin provider.

flask setup-system-trigger-oauth-client \
  --provider github \
  --client-params '{"client_id":"...","client_secret":"..."}'

setup-datasource-oauth-client

Configure OAuth for a datasource plugin provider.

flask setup-datasource-oauth-client \
  --provider notion \
  --client-params '{"client_id":"...","client_secret":"..."}'

transform-datasource-credentials

Transform datasource credentials for a specific environment.

flask transform-datasource-credentials --environment online

migrate-data-for-plugin

Migrate existing data for the plugin system.

flask migrate-data-for-plugin

extract-plugins

Extract plugin definitions from existing configuration.

flask extract-plugins --output_file plugins.jsonl --workers 10

extract-unique-identifiers

Extract unique plugin identifiers.

flask extract-unique-identifiers \
  --input_file plugins.jsonl \
  --output_file unique_identifiers.json

install-plugins

Batch install plugins from extracted definitions.

flask install-plugins \
  --input_file plugins.jsonl \
  --output_file installed_plugins.jsonl \
  --workers 100

install-rag-pipeline-plugins

Install RAG pipeline plugins.

flask install-rag-pipeline-plugins \
  --input_file plugins.jsonl \
  --output_file installed_plugins.jsonl \
  --workers 100

Retention Commands (api/commands/retention.py)

clear-free-plan-tenant-expired-logs

Clear expired logs for free-plan tenants.

flask clear-free-plan-tenant-expired-logs \
  --days 30 \
  --batch 100 \
  --tenant_ids "uuid1,uuid2"

clean-workflow-runs

Delete expired workflow runs and related data.

flask clean-workflow-runs \
  --before-days 30 \
  --batch-size 200 \
  --dry-run

# Date range mode
flask clean-workflow-runs \
  --start-from "2026-01-01" \
  --end-before "2026-04-01"

# Relative range mode
flask clean-workflow-runs \
  --from-days-ago 90 \
  --to-days-ago 30

archive-workflow-runs

Archive workflow runs to S3-compatible storage.

flask archive-workflow-runs \
  --before-days 90 \
  --workers 4 \
  --limit 1000 \
  --delete-after-archive \
  --dry-run

# Grayscale rollout
flask archive-workflow-runs \
  --tenant-ids "uuid1,uuid2" \
  --before-days 90

restore-workflow-runs

Restore archived workflow runs.

flask restore-workflow-runs \
  --tenant-ids "uuid1" \
  --run-id "run-uuid" \
  --workers 4 \
  --limit 100

delete-archived-workflow-runs

Delete archived workflow runs from the database.

flask delete-archived-workflow-runs \
  --tenant-ids "uuid1" \
  --run-id "run-uuid" \
  --dry-run

cleanup_orphaned_draft_variables

Remove orphaned draft variables.

flask cleanup_orphaned_draft_variables \
  --dry-run \
  --batch-size 1000 \
  --max-apps 100 \
  --force

clean-expired-messages

Clean expired messages.

flask clean-expired-messages \
  --before-days 90 \
  --from-days-ago 180 \
  --batch-size 1000 \
  --graceful-period 21 \
  --dry-run

export-app-messages

Export messages for an app to JSONL.GZ.

flask export-app-messages \
  --app-id "app-uuid" \
  --end-before "2026-06-01" \
  --filename "export/messages" \
  --batch-size 1000 \
  --use-cloud-storage \
  --dry-run

Storage Commands (api/commands/storage.py)

clear-orphaned-file-records

Remove database records for files that no longer exist in storage.

flask clear-orphaned-file-records --force

remove-orphaned-files-on-storage

Delete storage files that have no corresponding database records.

flask remove-orphaned-files-on-storage --force

file-usage

Query where files are referenced in the system.

flask file-usage --file-id "uuid"
flask file-usage --key "upload_files/path"
flask file-usage --src "documents.%" --limit 50 --json

migrate-oss

Migrate files from local/OpenDAL to cloud storage.

flask migrate-oss \
  --source opendal \
  --path upload_files \
  --path image_files \
  --overwrite \
  --update-db \
  --dry-run

Default paths: privkeys, upload_files, image_files, tools, website_files, keyword_files, ops_trace.

System Commands (api/commands/system.py)

reset-encrypt-key-pair

Reset workspace asymmetric key pair for credential encryption.

flask reset-encrypt-key-pair

Caution

This invalidates ALL stored LLM credentials across ALL workspaces. Every model provider must be re-configured after running this command. Only use when the key pair is compromised. Only works in SELF_HOSTED mode.

convert-to-agent-apps

Convert legacy Agent Assistant apps to the new Agent App type.

flask convert-to-agent-apps

upgrade-db

Run pending database migrations.

flask upgrade-db

fix-app-site-missing

Repair apps that are missing their associated site records.

flask fix-app-site-missing

Vector Commands (api/commands/vector.py)

vdb-migrate

Migrate vectors between backends.

flask vdb-migrate --scope all

The --scope option accepts all (default) to migrate all datasets.

add-qdrant-index

Add an index to Qdrant collections.

flask add-qdrant-index --field metadata.doc_id

old-metadata-migration

Migrate legacy vector metadata format.

flask old-metadata-migration

Quick Reference

Docker Commands

# Start all services
docker compose up -d

# Stop all services
docker compose down

# View logs
docker compose logs -f api
docker compose logs --tail 100 worker

# Restart a service
docker compose restart api

# Shell into container
docker compose exec api bash
docker compose exec db psql -U postgres dify

# Check health
curl http://localhost/health
curl http://localhost/ping

Common Operations Cheat Sheet

Task Command
Run DB migrations flask upgrade-db
Reset user password flask reset-password --email <e> --new-password <pw> --password-confirm <pw>
Create workspace flask create-tenant --email <e> --name <n>
Migrate vector DB flask vdb-migrate --scope all
Clean old workflow data flask clean-workflow-runs --before-days 30
Export messages flask export-app-messages --app-id <id> --end-before <date>
Migrate storage flask migrate-oss --source opendal --update-db
Reset encryption keys flask reset-encrypt-key-pair
Clean orphaned files flask clear-orphaned-file-records -f
Env sync after upgrade python docker/dify-env-sync.py

API Surface Summary

Surface Base Path Auth Audience
Console API /console/api/* JWT Web UI
Service API /v1/* API Key Integrations
Web API /api/* App token End users
Inner API /inner/api/* Shared secret Plugin daemon

System Endpoints

Endpoint Purpose
GET /health Full health check
GET /ping Liveness probe
GET /version API version
GET /init Setup status
GET /db-pool-stat DB pool stats
GET /threads Thread count

Port Reference

Port Service Protocol
80 nginx HTTP
443 nginx HTTPS
3000 web (Next.js) HTTP
5001 api (Flask) HTTP + WebSocket
5002 plugin_daemon HTTP
5003 plugin remote install HTTP
5432 PostgreSQL TCP
6379 Redis TCP
8080 Weaviate HTTP HTTP
50051 Weaviate gRPC gRPC
8194 sandbox HTTP
3128 ssrf_proxy HTTP