Skip to Content
DeerFlow

Configuration

DeerFlow App is configured through two files and a set of environment variables. This page covers the application-level configuration that most operators need to set up before deploying.

Configuration files

FilePurpose
config.yamlBackend configuration: models, sandbox, tools, skills, memory, and all Harness settings
extensions_config.jsonMCP servers and skill enable/disable state (managed by the App UI and Gateway API)

Frontend environment variables control the Next.js build and runtime behavior.

config.yaml

Start by copying the example:

cp config.example.yaml config.yaml

The most important sections for application configuration are:

Models

Configure the LLM providers the agent can use. At least one model is required.

models: - name: gpt-4o use: langchain_openai:ChatOpenAI model: gpt-4o api_key: $OPENAI_API_KEY request_timeout: 600.0 max_retries: 2 supports_vision: true

Reasoning capabilities

supports_thinking and supports_reasoning_effort only say whether a knob exists. When a provider’s contract differs from DeerFlow’s generic assumptions — thinking that cannot be turned off, or an effort vocabulary other than minimal/low/medium/high — declare a mapping-valued reasoning block instead. The two booleans are then derived from it, the chat UI offers only the values the model accepts, and every model call (chat, summarization, title generation, subagents) follows the same policy. Existing Ollama reasoning: true / false values, and the low / medium / high level strings gpt-oss style models take, remain native ChatOllama settings and do not opt into this contract.

models: - name: glm-5.3-flash use: deerflow.models.patched_deepseek:PatchedChatDeepSeek model: glm-5.3-flash api_base: https://api.z.ai/api/paas/v4 api_key: $ZAI_API_KEY supports_vision: true reasoning: thinking: required # unsupported | optional | required dialect: openai_extra_body # auto | openai_extra_body | anthropic | vllm_chat_template | ollama | none history: clear # preserve | clear effort: values: [low, high, max] # the provider's own vocabulary default: high # used when the caller does not choose aliases: # DeerFlow generic value -> provider value minimal: low medium: high extra_body: tool_stream: true
  • thinking: required keeps thinking on even when a background caller asks for it off; set on_disable_request: reject to fail such calls instead.
  • Effort values outside values map through aliases or fall back to default; they never reach the provider. Effort values written into the profile or into when_thinking_enabled / when_thinking_disabled are validated against values at startup for the same reason.
  • When changing effort.path, remove old reasoning_effort keys from the profile and thinking templates. A declared contract rejects these conflicting keys at startup. The chat UI also drops a remembered provider-specific effort when switching to a legacy model that does not advertise it.
  • default also applies to callers that never choose an effort — summarization, title generation, and subagents — so pick a level you are happy to pay for on every background call (high above, with max left selectable in the composer).
  • dialect: auto (the default) infers the on/off payload from when_thinking_enabled, so existing profiles can add reasoning without rewriting their templates. Profiles without a reasoning block behave exactly as before.
  • when_thinking_enabled and when_thinking_disabled are deep-merged into the profile’s settings: a template can add or override keys, never remove them, so the profile’s other extra_body keys (for example tool_stream) survive both toggles. Put enable-only keys such as extra_body.thinking.budget_tokens in when_thinking_enabled, not in the profile’s base extra_body — a disable template cannot clear them, and Anthropic-style APIs reject them beside type: disabled.
  • Contradictory profiles (for example required together with when_thinking_disabled) fail at startup.

Sandbox

Choose the execution environment for agent file and command operations:

sandbox: use: deerflow.sandbox.local:LocalSandboxProvider allow_host_bash: false # set true only for trusted single-user workflows

Tools

Configure which tools the agent has access to. The defaults use DuckDuckGo (no API key) and Jina AI for web operations:

tools: # Web search (choose one) - use: deerflow.community.ddg_search.tools:web_search_tool # default, no key required # - use: deerflow.community.tavily.tools:web_search_tool # api_key: $TAVILY_API_KEY # Web fetch (choose one) - use: deerflow.community.jina_ai.tools:web_fetch_tool # Image search - use: deerflow.community.image_search.tools:image_search_tool # File operations - use: deerflow.sandbox.tools:ls_tool - use: deerflow.sandbox.tools:read_file_tool - use: deerflow.sandbox.tools:glob_tool - use: deerflow.sandbox.tools:grep_tool - use: deerflow.sandbox.tools:write_file_tool - use: deerflow.sandbox.tools:str_replace_tool - use: deerflow.sandbox.tools:bash_tool

Database backend

DeerFlow uses the database section for both LangGraph checkpoint data and application data such as runs, feedback, and thread metadata.

By default, DeerFlow uses SQLite for local, single-node persistence:

database: backend: sqlite sqlite_dir: .deer-flow/data

SQLite mode stores everything in one deerflow.db file. This is fine for development or single-user deployments, but concurrent production traffic can hit SQLite’s single-writer limit and raise sqlite3.OperationalError: database is locked.

For production or multi-user deployments, use Postgres:

database: backend: postgres postgres_url: $DATABASE_URL run_events: backend: db

Set DATABASE_URL in your environment, for example postgresql://user:password@localhost:5432/deerflow.

Install PostgreSQL support for local runs:

cd backend && uv sync --all-packages --extra postgres

For Docker or scripted starts, set UV_EXTRAS=postgres before installing or building. The legacy standalone checkpointer section is still accepted for compatibility, but prefer database for new deployments.

Memory

memory: enabled: true injection_enabled: true manager_class: deermem # backend selector: deermem | noop | openviking | dotted path mode: middleware # middleware (default) | tool (experimental) backend_config: # DeerMem-private knobs (the backend self-interprets these) storage_path: "" # empty = deer-flow base_dir (per-user memory under it) debounce_seconds: 30 max_facts: 100 fact_confidence_threshold: 0.7 max_injection_tokens: 2000 # model: # LLM for extraction; omit all fields = use the app default model # provider: openai # model: gpt-4o-mini # api_key: $OPENAI_API_KEY

The optional openviking backend connects to an independent OpenViking server through langchain-openviking and currently supports one DeerFlow user in mode: middleware. Its private configuration uses base_url, owner_user_id, api_key_env, failure_policy, and retrieval with an ordinary OpenViking USER API key instead of the DeerMem fields shown above. See docs/OPENVIKING.md in the repository for the complete configuration and Docker startup sequence.

Frontend environment variables

Set these before running pnpm build or starting the frontend in production:

VariableRequiredDescription
BETTER_AUTH_SECRETRequired in productionSecret for session signing. Use openssl rand -base64 32.
BETTER_AUTH_URLRecommendedPublic-facing base URL (e.g., https://your-domain.com)
SKIP_ENV_VALIDATIONOptionalSet to 1 to skip env validation during build (not recommended)
NEXT_PUBLIC_BACKEND_BASE_URLOptionalOverride the Gateway base URL used for REST and SSR calls
NEXT_PUBLIC_LANGGRAPH_BASE_URLOptionalOverride the LangGraph API base URL (defaults to <backend>/api)

In development, set these in a .env file at the repo root:

BETTER_AUTH_SECRET=your-strong-secret-here-min-32-chars

extensions_config.json

This file manages MCP server connections and skill enable/disable state. It is created automatically when you first manage extensions through the App UI or Gateway API.

Manual example:

{ "mcpServers": { "my-server": { "command": "npx", "args": ["-y", "@my-org/my-mcp-server"], "enabled": true } }, "skills": { "deep-research": { "enabled": true }, "data-analysis": { "enabled": true } } }

Config upgrade

When the config schema changes, config_version is bumped. To merge new fields into your existing config without losing customizations:

make config-upgrade

Runtime environment variables

DeerFlow reads these from its own process environment — via a .env file, the Docker environment, or the shell.

Only DEER_FLOW_SKILLS_PATH resolves a relative value against DEER_FLOW_PROJECT_ROOT. DEER_FLOW_HOME and DEER_FLOW_CONFIG_PATH are used as given, so a relative value resolves against the process working directory — set both to absolute paths so writable state and the loaded config file land where you expect them.

VariableDefaultDescription
DEER_FLOW_PROJECT_ROOTcurrent working directoryRoot for project-relative defaults, including the skills lookup
DEER_FLOW_HOME<project root>/.deer-flowWritable directory for runtime state (threads, uploads); use an absolute path
DEER_FLOW_CONFIG_PATHauto-discovered under project rootAbsolute path to config.yaml
DEER_FLOW_SKILLS_PATH<project root>/skillsDirectory containing skill definitions (a relative value resolves against the project root)
AUTH_JWT_SECRETauto-generatedJWT signing secret for the Gateway

Log verbosity is not an environment variable — set log_level in config.yaml instead (debug, info, warning, or error; default info). See Harness Configuration for the module reference.

DEER_FLOW_ROOT is a host-side variable for the Docker Compose dev stack only; the DeerFlow process does not read it. See the Deployment Guide.

When AUTH_JWT_SECRET is unset, DeerFlow generates a secret on first start and persists it to .jwt_secret, so sessions survive restarts. Set it explicitly in production to keep a stable, secret value.