# Extension points — langgenius/dify

> Canonical page: https://codevetter.com/unpack/dify/extension-points

# Extension points — langgenius/dify

Scanned commit 3a017e8cccb316f23f601af65d2e8ce92e68f788 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Dify is built for extension at every layer: app modes via generator classes + a match-dispatch, workflow nodes via `DifyNodeFactory`/`resolve_workflow_node_class` (with most builtins now in the external `graphon` package), vector/trace backends via Python entry-point packages, storage via a `StorageType` match, remote config via named sources, HTTP routes via flask-restx Namespaces + module import lists, Celery work via the imports+beat_schedule assembly, moderation/tool/providers via factories and the external plugin daemon, CLI verbs via a generated command tree, and frontend calls via regenerated oRPC contracts.
- New app types plug in at three coordinated points: extend `AppMode` in `models/model.py`, add a generator under `core/app/apps/<mode>/` subclassing `BaseAppGenerator`, and add a `case` in `AppGenerateService._dispatch_generate`. — [api/models/model.py#L374-385](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/models/model.py#L374-L385) [api/services/app_generate_service.py#L188-358](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/services/app_generate_service.py#L188-L358) [api/core/app/apps](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/app/apps)
- Workflow node types resolve through `core/workflow/node_factory.py` (`DifyNodeFactory`, `resolve_workflow_node_class`, `is_start_node_type`); Dify-owned node dirs (`agent`, `agent_v2`, `datasource`, `human_input`, `knowledge_index`, `knowledge_retrieval`, `trigger_*`) coexist with `graphon.nodes.BuiltinNodeTypes` from the external engine package. — [api/core/workflow/node_factory.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/workflow/node_factory.py) [api/core/workflow/nodes](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/workflow/nodes) [api/core/workflow/workflow_entry.py#L19-24](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/workflow/workflow_entry.py#L19-L24)
- Vector backends are true plugins: each `api/providers/vdb/vdb-*` package declares `[project.entry-points."dify.vector_backends"]` (e.g. `pgvector = "dify_vdb_pgvector.pgvector:PGVectorFactory"`) and joins the uv workspace via `tool.uv.workspace.members`. — [api/providers/vdb/vdb-pgvector/pyproject.toml#L12-14](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/providers/vdb/vdb-pgvector/pyproject.toml#L12-L14) [api/pyproject.toml#L58-61](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/pyproject.toml#L58-L61)
- Tracing providers mirror the vdb pattern: `api/providers/trace/*` workspace packages (aliyun, arize-phoenix, langfuse, langsmith, mlflow, opik, tencent, weave) selected via `trace-*` dependency groups. — [api/pyproject.toml#L291-308](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/pyproject.toml#L291-L308)
- Storage backends extend `StorageType` + a `case` in `Storage.get_storage_factory` returning a `BaseStorage` runner; implementations live in `api/extensions/storage/` (s3, opendal, azure_blob, gcs, oss, cos, oci, obs, baidu, supabase, tos, clickzetta_volume). — [api/extensions/ext_storage.py#L21-50](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_storage.py#L21-L50) [api/extensions/storage](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/storage)
- Config additions go into the right `configs/` mixin group (deploy/enterprise/extra/feature/middleware/observability/packaging/remote_settings_sources) and are picked up by pydantic-settings; remote sources extend `RemoteSettingsSourceName` + a `case` in `RemoteSettingsSourceFactory`. — [api/configs/app_config.py#L40-47](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/configs/app_config.py#L40-L47) [api/configs/app_config.py#L89-92](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/configs/app_config.py#L89-L92) [api/configs](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/configs)
- New HTTP routes: add a flask-restx `Namespace` resource module under the right `controllers/` blueprint package; console modules must be imported in `controllers/console/__init__.py` (`RESOURCE_MODULES` tuple or the `from . import …` blocks) so route decorators evaluate. — [api/controllers/console/__init__.py#L40-70](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/controllers/console/__init__.py#L40-L70) [api/extensions/ext_blueprints.py#L28-38](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_blueprints.py#L28-L38)
- New Celery work: add module path to `ext_celery.init_app`'s `imports` list, gate it with an `ENABLE_*` flag in `CeleryScheduleTasksConfig`, and add a `beat_schedule` entry for periodic jobs — the file explicitly asks contributors to add the switch. — [api/extensions/ext_celery.py#L172-188](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_celery.py#L172-L188)
- Model/tool/agent-strategy providers live in the external plugin daemon, not this repo: new capabilities surface to the API through `core/plugin/impl/*` clients and are installed via marketplace; local extension is via `ext_code_based_extension` + `api_based_extension` external-data-tool hooks. — [api/core/plugin/impl](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/plugin/impl) [api/extensions/ext_code_based_extension.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/extensions/ext_code_based_extension.py) [api/services/api_based_extension_service.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/services/api_based_extension_service.py)
- Moderation backends plug into `core/moderation/factory.py` with existing `keywords`, `openai_moderation`, and `api` implementations as templates. — [api/core/moderation](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/moderation)
- CLI verbs: create `cli/src/commands/<topic>/<verb>/index.ts` extending `DifyCommand` (sibling `run.ts`/`handlers.ts`/`guide.ts` optional; `_shared/` excluded from discovery), then `pnpm tree:gen` regenerates `tree.generated.ts` — CI gates drift with `tree:check`. — [cli/src/commands/tree.generated.ts#L1-4](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/cli/src/commands/tree.generated.ts#L1-L4) [cli/src/commands](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/cli/src/commands)
- Frontend↔backend contract extension is generated, not handwritten: new console endpoints flow through `api/controllers` schemas → `api/dev/generate_swagger_specs.py`/`generate_fastopenapi_specs.py` → `packages/contracts` `gen-api-contract` (openapi-ts) → consumed via `consoleClient`/`consoleQuery`; AGENTS.md forbids handwritten REST helpers or direct edits to generated contracts. — [packages/contracts/package.json#L37-42](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/packages/contracts/package.json#L37-L42) [web/service/console/index.ts#L29-37](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/web/service/console/index.ts#L29-L37) [web/AGENTS.md](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/web/AGENTS.md)
- GraphEngine behavior is layered: callers pass `graph_engine_layers: Sequence[GraphEngineLayer]` (e.g. `DebugLoggingLayer`, `ExecutionLimitsLayer`, `ObservabilityLayer`, `PauseStatePersistenceLayer`) into generators/`WorkflowEntry`, so cross-cutting run behavior extends via engine layers rather than engine edits. — [api/core/app/apps/workflow/app_generator.py#L106-108](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/app/apps/workflow/app_generator.py#L106-L108) [api/core/workflow/workflow_entry.py#L42-43](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/workflow/workflow_entry.py#L42-L43) [api/core/app/layers/pause_state_persist_layer.py](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/app/layers/pause_state_persist_layer.py)
- Response-stream processing is a filter chain: `filter_graph_events` accepts additional `ResponseStreamFilter`-style filters (e.g. `HumanInputFormEventFilter`), letting new event semantics be inserted without touching engine internals. — [api/core/workflow/workflow_entry.py#L56-79](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/core/workflow/workflow_entry.py#L56-L79)
- New Flask extensions follow the `extensions/ext_*` convention: implement `init_app(app)` (optionally `is_enabled()`), add to the ordered list in `initialize_extensions` at the correct dependency position. — [api/app_factory.py#L175-259](https://github.com/langgenius/dify/blob/3a017e8cccb316f23f601af65d2e8ce92e68f788/api/app_factory.py#L175-L259)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
