--- title: "Configuration forms" description: "Auto-generate node configuration forms from JSON Schema." source: https://flowdrop.io/docs/editor/config-schema site: FlowDrop documentation --- # Configuration forms FlowDrop automatically generates configuration forms from JSON Schema definitions. This guide covers static schemas, dynamic runtime forms, and layout control. ## Overview FlowDrop provides three ways to define configuration forms for nodes: | Approach | When to use | | ------------------------------------------ | ------------------------------------------------- | | **Static `configSchema`** | Fields are known ahead of time | | **Dynamic `configEdit.dynamicSchema`** | Fields depend on external data or user selections | | **External `configEdit.externalEditLink`** | Configuration is managed by a 3rd-party system | All three approaches can be combined — FlowDrop tries the dynamic schema first, then falls back to the static schema if the fetch fails. ## Quick Start Define `configSchema` on your node metadata. FlowDrop auto-renders the form: ```json highlight={4-32} { "id": "calculator", "name": "Calculator", "configSchema": { "type": "object", "properties": { "operation": { "type": "string", "title": "Operation", "description": "Mathematical operation to perform", "default": "add", "enum": [ "add", "subtract", "multiply", "divide", "power", "sqrt", "average", "min", "max", "median", "mode" ] }, "precision": { "type": "integer", "title": "Precision", "description": "Number of decimal places", "default": 2 } } }, ... } ``` {/* SCREENSHOT (Tier 1 — HIGH). Capture: the config panel rendered from a schema, showing several field types — text input, number/slider, toggle, select, and a multiline textarea. Produce with the editor against example-server-express. Swap the placehold.co URL for /images/screenshots/config-form.png when ready. */} ![Config panel showing a form auto-generated from a JSON Schema: text input, number slider, toggle, dropdown select, and multiline textarea fields.](/images/screenshots/calculator-node.webp) ## Field Types and Formats ### Basic Types | `type` | Renders as | | --------- | --------------------- | | `string` | Text input | | `number` | Number input | | `integer` | Integer input | | `boolean` | Toggle switch | | `array` | Repeatable field list | | `object` | Nested fieldset | ### Format Overrides Use `format` to change how a field renders: | Format | Renders as | Notes | | -------------- | ------------------------ | --------------------------------------- | | `multiline` | Textarea | Multi-line text input | | `hidden` | Nothing | Stored in config but not shown in UI | | `range` | Slider | Requires `minimum` and `maximum` | | `json` | CodeMirror editor | JSON syntax highlighting and validation | | `code` | CodeMirror editor | Alias for `json` | | `markdown` | Markdown editor | Toolbar and preview | | `template` | CodeMirror editor | `{{ variable }}` autocomplete | | `autocomplete` | Text input + suggestions | Fetches options from API | ### Example ```json { "type": "object", "properties": { "prompt": { "type": "string", "title": "Prompt", "format": "multiline" }, "temperature": { "type": "number", "title": "Temperature", "format": "range", "minimum": 0, "maximum": 2, "default": 0.7 }, "metadata": { "type": "object", "title": "Metadata", "format": "json" }, "internalId": { "type": "string", "format": "hidden" } } } ``` ## Select Fields ### Simple Enum ```json { "model": { "type": "string", "title": "Model", "enum": ["gpt-4o", "gpt-4o-mini", "claude-3"], "default": "gpt-4o-mini" } } ``` ### Labeled Options with `oneOf` ```json { "status": { "type": "string", "title": "Status", "oneOf": [ { "const": "pending", "title": "Pending" }, { "const": "in_progress", "title": "In Progress" }, { "const": "completed", "title": "Completed" } ] } } ``` ### Multi-Select (Checkboxes) ```json { "tags": { "type": "string", "title": "Tags", "enum": ["urgent", "review", "archive"], "multiple": true } } ``` ## Autocomplete Fields Fetch suggestions from a remote API as the user types: ```json { "userId": { "type": "string", "title": "User", "format": "autocomplete", "autocomplete": { "url": "/api/users/search", "queryParam": "q", "minChars": 2, "debounceMs": 300, "labelField": "name", "valueField": "id", "allowFreeText": false, "fetchOnFocus": true } } } ``` ## Template Fields Template fields provide CodeMirror editing with `{{ variable }}` syntax highlighting and autocomplete from connected node outputs: ```json { "prompt": { "type": "string", "title": "Prompt Template", "format": "template", "variables": { "ports": ["data", "context"], "showHints": true } } } ``` ## UISchema Layout By default, fields render in property order. Use `uiSchema` to control layout and grouping — inspired by [JSON Forms](https://jsonforms.io/): ```json { "type": "VerticalLayout", "elements": [ { "type": "Control", "scope": "#/properties/name" }, { "type": "Control", "scope": "#/properties/model" }, { "type": "Group", "label": "Advanced Settings", "collapsible": true, "defaultOpen": false, "elements": [ { "type": "Control", "scope": "#/properties/temperature" }, { "type": "Control", "scope": "#/properties/maxTokens" } ] } ] } ``` ### Element Types | Type | Description | | ---------------- | ----------------------------------------------------------------------- | | `Control` | Renders a single form field. `scope` is a JSON Pointer to the property. | | `VerticalLayout` | Stacks child elements vertically. | | `Group` | Wraps elements in a collapsible fieldset with a label. | ## Special Config Properties Certain property names trigger automatic behaviors: | Property | Type | Behavior | | --------------------- | --------------- | ------------------------------------------------ | | `instanceTitle` | `string` | Overrides the node's displayed title | | `instanceDescription` | `string` | Overrides the node's displayed description | | `instanceBadge` | `string` | Overrides the node's badge | | `nodeType` | `string` | Switches visual rendering type | | `dynamicInputs` | `DynamicPort[]` | Creates user-defined input handles | | `dynamicOutputs` | `DynamicPort[]` | Creates user-defined output handles | | `branches` | `Branch[]` | Creates conditional output paths (gateway nodes) | ## Dynamic Schema (Runtime) Use `configEdit.dynamicSchema` to fetch config schemas from your backend at runtime: ```typescript const myNode: NodeMetadata = { node_type_id: 'dynamic-processor', name: 'Dynamic Processor', configEdit: { dynamicSchema: { url: '/api/nodes/{nodeTypeId}/schema', method: 'GET', parameterMapping: { nodeTypeId: 'metadata.node_type_id' }, cacheSchema: true, timeout: 10000 }, showRefreshButton: true }, // Fallback static schema configSchema: { type: 'object', properties: { apiKey: { type: 'string', title: 'API Key' } } } }; ``` The dynamic schema endpoint should return a JSON Schema object. Multiple response shapes are accepted: - Direct schema: `{ type: "object", properties: {...} }` - Wrapped: `{ data: {...} }` or `{ schema: {...} }` - With UISchema: `{ configSchema: {...}, uiSchema: {...} }` ## External Edit Links For configuration managed by a 3rd-party system: ```typescript configEdit: { externalEditLink: { url: 'https://admin.example.com/nodes/{nodeTypeId}/configure', label: 'Configure in Admin Portal', icon: 'mdi:open-in-new', parameterMapping: { nodeTypeId: 'metadata.node_type_id' }, openInNewTab: true } } ``` ## Standalone ConfigForm You can render the `ConfigForm` component independently in svelte projects: ```svelte { values = config; }} onSave={(config) => { /* persist */ }} /> ```