SuperAPI AI Directory

dify-docs-env-vars

Deployment & operations

View repository

Updated 10-15 23:48

About this skill

Dify Environment Variable Documentation

Not an entry point — run under dify-docs-write; the procedure below implements its stages for en/self-host/deploy/configuration/environments.mdx. Read references/style-overrides.md (in this skill directory — env-var-specific style rules and description anti-patterns) together with this pack. Use the ref pinned at S1; cite it in the S4 scope report.

Procedure (S2 → S6)

Work through in order. Every variable goes through steps 1–4 without exception — do not skip a variable because it seems "obvious".

Step 1 (S2): Trace each variable in the codebase

When using subagents for tracing, assign 3–5 related variables per agent. Tracing depth depends on variable type:

Variable type Depth
Python config vars (defined in api/configs/) Full trace (below).
Frontend vars (mapped in web/docker/entrypoint.sh) Trace the Docker-to-NEXT_PUBLIC_* mapping in entrypoint.sh; verify the default in both docker/.env.example and web/.env.example; run grep -rn "<VAR_NAME>" <path-to-dify-repo>/api/ — any match means the var is dual-purpose and needs a full trace.
Docker/container service vars (only in docker-compose.yaml) grep -rn "<VAR_NAME>" <path-to-dify-repo>/api/ must return no matches; then document from .env.example comments.
Plugin daemon vars (PLUGIN_* not in api/configs/) Document from .env.example comments.

Full trace:

  1. Find the definition in api/configs/ — Pydantic field type, default, description, and any validation_alias (fallback) settings.
  2. Find every usage — grep both the env var name and the Python attribute (dify_config.VARIABLE_NAME); read the surrounding code.
  3. Determine behavior when empty vs set — trace fallback chains; identify what breaks.

Step 2 (S2): Write a plain-language explanation

Cover: what the variable does in practical terms; the specific features that depend on it (name them); what happens if left empty; what happens if set; key code file paths (no line numbers — they shift). This explanation goes into the S4 scope report.

Step 3 (S5): Write the user-facing description

  • Lead with the practical impact, not the technical mechanism
  • Name the features that require the variable (e.g., "Required for the Human Input node")
  • Explain what breaks if misconfigured (e.g., "If empty, email links will be broken")
  • Mention fallback behavior if any (e.g., "falls back to CONSOLE_API_URL")
  • Include relationships with other variables when relevant
  • Apply every rule in references/style-overrides.md

Step 4 (S4 contribution): Report

The S4 scope report presents: the plain-language explanations, the proposed descriptions, and the pinned ref. The pipeline's S4 gate applies.

Step 5 (S5/S6): Edit the documentation

Edit en/self-host/deploy/configuration/environments.mdx following Document Structure. Update the zh/ and ja/ copies in the same pass, per tools/translate/formatting-zh.md, tools/translate/formatting-ja.md, and writing-guides/glossary.md.

S7 verifiers

Run the verifier

The canonical command scans BOTH env sources — never pass only one:

python3 .claude/skills/dify-docs-env-vars/verify-env-docs.py \
  --env-example <path-to-dify-repo>/docker/.env.example \
  --env-example <path-to-dify-repo>/docker/envs \
  --compose <path-to-dify-repo>/docker \
  --docs en/self-host/deploy/configuration/environments.mdx

--compose reads the ${VAR} references in docker/docker-compose*.y*ml. A variable a compose file consumes with no .env.example entry is invisible to every other check — EXPOSE_WEAVIATE_GRPC_PORT went undocumented for eleven months that way — so the script lists them under === IN COMPOSE BUT NOT IN ANY .env.example (<n>) === and treats them as source variables from then on. --compare-rev reads the compose files at both refs on its own. docker-compose.pytest.ports.yaml is skipped in both modes and the skip is printed: it publishes vector-store ports for the integration tests, and nothing a deployment reads.

--env-example is repeatable; a directory argument is globbed **/*.env.example recursively. The script first prints the list of files it parsed — confirm it shows docker/.env.example plus the files under docker/envs/, then the compose file count. A single-source run under-scans and produces false "extra in docs" results.

Output contract: on a fully clean doc the last line is ALL CHECKS PASSED — documentation matches .env.example and the script exits 0; otherwise it prints TOTAL ISSUES: <n> with per-category counts and exits 1.

Cadence. The full command above is the baseline audit, and the baseline was cleared at dify tag 1.17.1. A release pass runs --compare-rev — it diffs both the .env.example files and the compose references between two refs, so a clean baseline stays clean incrementally. Re-run the full command whenever this script, the ignore list's location, or the .env.example layout changes, and after any pass that touched more than a handful of variables; it must end on ALL CHECKS PASSED or every remaining line must be accounted for in the ignore list. Run it against the zh and ja pages too — the parser understands 默认值:, デフォルト値: and (空), so their counts are as meaningful as English's.

Pass bar for every task: the full command ends on ALL CHECKS PASSED, or every remaining line is accounted for in the ignore list with a reason. Missing from docs stopped being standing backlog when the baseline was cleared at tag 1.17.1: a nonzero count now means a variable arrived since, and it is documented or ignored before the task ends. If the script prints WARNING: ignore list not found, it stops with exit status 2 and prints no counts: fix the path and re-run.

Update the ignore list if needed

The verifier filters out variables listed in the registry's guides/env-ignored-vars.md. That list stays in the private registry because its entries name unreleased work. The verifier finds it through $DIFY_DOCS_REGISTRY or a sibling clone of this repo; pass --ignored PATH to point somewhere else. When you:

  • Remove a variable from the docs as Cloud-only → add it under Cloud-only (SaaS).
  • Skip documenting an experimental or internal flag → add it under Experimental / internal.
  • Document a supported variable whose .env.example entry is commented out (#FOO=bar) → add it under Verifier false positives. This bucket is only for vars present in .env.example in commented form; see Source of Truth for vars absent entirely.

Every entry must include a source reference (PR, commit, or audit date).

Source of Truth

After Dify PR #31586, the supported self-host knob surface is split across:

  • docker/.env.example — essential startup values
  • docker/envs/**/*.env.example — categorized optional vars (core-services, databases, infrastructure, security, vectorstores, middleware)

The verifier reads both — always use the canonical verifier command above, which passes both sources.

Var location Action
In any .env.example file, uncommented Document.
In any .env.example file, commented (#FOO=bar) Document; add to Verifier false positives in env-ignored-vars.md (the verifier can't parse defaults from comments).
Only in api/configs/ Pydantic, not in any .env.example Don't document. Upstream-deferred; file a PR adding it to the appropriate .env.example file first.
In .env.example and still parsed, but upstream-deprecated with a replacement Keep the row; lead the description with the deprecation and the replacement: "Deprecated; use X." Deprecated means still parsed — a removed var never gets a Deprecated label.
Removed from .env.example because the code no longer reads it Remove from docs — no tombstone rows (a documented row implies the var still takes effect). If a successor variable replaced it, add one clause to the successor's description so the old names stay findable via search: "Replaces the former EDITION, ignored from 1.17.0 onward." With no successor, remove without trace; upgrader discoverability belongs in upstream Dify release notes.

The verifier's "extra in docs" signal is not an escape hatch. Never suppress it for Pydantic-only vars via env-ignored-vars.md.

Document Structure

The doc groups variables by subsystem, broadly following the docker/.env.example and docker/envs/** layout (Common Variables, Server Configuration, Web Frontend Service, Database Service, and so on). Match an existing ## section for a new variable; don't invent one. If a variable genuinely fits no section, raise it with the user rather than guessing.

Element Use for
Tables Groups of related, straightforward variables (connection settings, credentials, tuning knobs).
Individual headings Important variables needing explanation — enum-type selectors (STORAGE_TYPE, VECTOR_STORE) or variables where the "why" matters (SECRET_KEY, FILES_URL).
Tabs Frontend variables where Docker and source deployments use different names. Tabs cannot sit inside table cells, so tabbed variables need individual headings.
Accordions Provider-specific configuration (storage backends, vector databases, mail providers) — users only need one provider.

Reader Persona

Same audience as en/self-host/deploy/ documentation (see the dify-docs-guides pack): DevOps engineers and system administrators deploying Dify. Assume strong infrastructure knowledge. Readers are actively configuring a deployment and scanning for a specific variable, not reading linearly. They need to know what each variable does, when to change it, and what breaks if they get it wrong.