docs/versioned_docs/version-1.10.0/Develop/extensions-manifest.mdx
This page is the reference for the extension.json manifest the Langflow Extension loader consumes.
The canonical JSON Schema lives at https://schemas.langflow.org/extension/v1.json and is generated from the Pydantic model at lfx.extension.manifest.ExtensionManifest.
To export the live schema, run:
lfx extension schema --output extension.schema.json
Use the $schema reference in your manifest so editors can autocomplete and validate inline:
{
"$schema": "https://schemas.langflow.org/extension/v1.json",
"id": "lfx-my-extension",
"version": "0.1.0",
"name": "My extension",
"lfx": { "compat": ["1"] },
"bundles": [{ "name": "my_bundle", "path": "components/my_bundle" }]
}
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Globally-unique extension ID. Lowercase, hyphenated, starts with a letter, 2-64 chars. Convention: lfx-<name>. |
version | string | yes | SemVer 2.0.0 version string for this extension release. |
name | string | yes | Human-readable display name shown in the Langflow palette. 1-200 chars. |
description | string | null | no | Optional one-paragraph summary, max 2000 chars. |
lfx | object | yes | Compatibility declaration against the BUNDLE_API contract. |
bundles | array | yes | Bundle list. v0 accepts exactly one bundle. |
capabilities | object | no | Optional capability flags. Defaults to all-false. |
$schema | string | no | Optional pointer to this JSON Schema; editors use it for autocomplete. |
additionalProperties: false — any field not listed here is rejected with a typed error. Reserved names (services, routes, hooks, starterProjects, userConfig) are documented under Deferred fields and surface a more specific error code.
lfx: compatibility declaration"lfx": { "compat": ["1"] }
| Field | Type | Description |
|---|---|---|
compat | array of strings | Non-empty list of BUNDLE_API.md contract versions this extension supports. Each entry is a positive-integer string. |
The runtime compares str(BUNDLE_API_VERSION) against this list. A mismatch fails install with version-constraint-unsatisfied. v0 accepts only "1"; lists like ["1", "2"] become meaningful when a future BUNDLE_API revision ships.
bundles"bundles": [
{ "name": "my_bundle", "path": "components/my_bundle" }
]
| Field | Type | Description |
|---|---|---|
name | string | Bundle name; addressable as ext:<bundle>:<Class>@<slot>. Lowercase snake_case, starts with a letter, 2-64 chars. |
path | string | Path to the bundle directory, relative to the manifest. Must not start with / or contain ... |
v0 enforces minItems: 1, maxItems: 1; multi-bundle extensions are rejected with multi-bundle-deferred-in-this-milestone and ship in a later epic.
capabilitiesOptional. Defaults to { "requiresCredentials": false }.
| Field | Type | Description |
|---|---|---|
requiresCredentials | bool | If true, the loader records that components in this bundle expect credential variables to be configured before use. |
Additional capability keys are rejected with extra="forbid" so a misspelled key surfaces immediately rather than silently turning a feature off.
The schema strips these names from the published properties map but reserves them via x-deferred-fields, so a manifest that sets one gets a specific error code instead of the generic "additional property" message.
| Reserved key | Replacement error code | Future epic |
|---|---|---|
services | field-deferred-in-this-milestone | B2 — non-component primitives |
routes | field-deferred-in-this-milestone | B2 — non-component primitives |
hooks | field-deferred-in-this-milestone | B2 — non-component primitives |
starterProjects | field-deferred-in-this-milestone | later milestone |
userConfig | field-deferred-in-this-milestone | later milestone |
A manifest that sets any of these to a non-null value is rejected at validate / load time. Setting them to null is allowed (the loader treats null and absent identically).
If you'd rather not ship a separate extension.json next to pyproject.toml, declare the same fields under [tool.langflow.extension]:
[tool.langflow.extension]
id = "lfx-my-extension"
version = "0.1.0"
name = "My extension"
[tool.langflow.extension.lfx]
compat = ["1"]
[[tool.langflow.extension.bundles]]
name = "my_bundle"
path = "components/my_bundle"
The loader prefers an extension.json when both exist. The Pydantic validator is the same so error codes and field semantics are identical.
The loader and validator both emit typed errors keyed by the manifest field that triggered them. The full code list is at lfx.extension.errors.ERROR_CODES; the codes most relevant when authoring a manifest are:
| Code | Cause |
|---|---|
manifest-invalid | Schema validation failed; the message names the field. |
manifest-not-found | No extension.json and no [tool.langflow.extension] section at the extension root. |
version-constraint-unsatisfied | lfx.compat does not include this Langflow's BUNDLE_API_VERSION. |
field-deferred-in-this-milestone | A reserved field was set to a non-null value. |
multi-bundle-deferred-in-this-milestone | bundles has more than one entry. |
path-escape | A bundles[].path resolves outside the manifest root (typically a symlink). |
bundle-path-not-found | bundles[].path does not exist or is not a directory. |
Run lfx extension validate <path> to see every error as a structured object with code, message, location, hint, and ref_url.