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
| File | Purpose |
|---|---|
config.yaml | Backend configuration: models, sandbox, tools, skills, memory, and all Harness settings |
extensions_config.json | MCP 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.yamlThe most important sections for application configuration are:
Models
Configure the LLM providers the agent can use. At least one model is required.
OpenAI
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: trueReasoning 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: truethinking: requiredkeeps thinking on even when a background caller asks for it off; seton_disable_request: rejectto fail such calls instead.- Effort values outside
valuesmap throughaliasesor fall back todefault; they never reach the provider. Effort values written into the profile or intowhen_thinking_enabled/when_thinking_disabledare validated againstvaluesat startup for the same reason. - When changing
effort.path, remove oldreasoning_effortkeys 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. defaultalso 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 (highabove, withmaxleft selectable in the composer).dialect: auto(the default) infers the on/off payload fromwhen_thinking_enabled, so existing profiles can addreasoningwithout rewriting their templates. Profiles without areasoningblock behave exactly as before.- Contradictory profiles (for example
requiredtogether withwhen_thinking_disabled) fail at startup.
Sandbox
Choose the execution environment for agent file and command operations:
Local (default)
sandbox:
use: deerflow.sandbox.local:LocalSandboxProvider
allow_host_bash: false # set true only for trusted single-user workflowsTools
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_toolDatabase 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/dataSQLite 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: dbSet 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 postgresFor 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_KEYThe 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:
| Variable | Required | Description |
|---|---|---|
BETTER_AUTH_SECRET | Required in production | Secret for session signing. Use openssl rand -base64 32. |
BETTER_AUTH_URL | Recommended | Public-facing base URL (e.g., https://your-domain.com) |
SKIP_ENV_VALIDATION | Optional | Set to 1 to skip env validation during build (not recommended) |
NEXT_PUBLIC_BACKEND_BASE_URL | Optional | Override the Gateway base URL used for REST and SSR calls |
NEXT_PUBLIC_LANGGRAPH_BASE_URL | Optional | Override 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-charsextensions_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-upgradeRuntime 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.
| Variable | Default | Description |
|---|---|---|
DEER_FLOW_PROJECT_ROOT | current working directory | Root for project-relative defaults, including the skills lookup |
DEER_FLOW_HOME | <project root>/.deer-flow | Writable directory for runtime state (threads, uploads); use an absolute path |
DEER_FLOW_CONFIG_PATH | auto-discovered under project root | Absolute path to config.yaml |
DEER_FLOW_SKILLS_PATH | <project root>/skills | Directory containing skill definitions (a relative value resolves against the project root) |
AUTH_JWT_SECRET | auto-generated | JWT 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.