---
title: "Custom nodes"
description: "Register custom Svelte components as workflow node types."
source: https://flowdrop.io/docs/editor/custom-nodes
site: FlowDrop documentation
---
# Custom nodes
FlowDrop ships with 7 built-in node types, but you can register your own custom node components to extend the editor.
## Overview
Registration happens against the instance's node registry, `fd.nodes` (a `NodeComponentRegistry`). There are three methods:
| Approach | When to use |
| --------------------------------------- | ------------------------------------------- |
| **`fd.nodes.registerCustom()`** | One-off project-specific nodes |
| **`fd.nodes.registerPlugin()`** | Libraries providing multiple node types |
| **`createPlugin().register(fd.nodes)`** | Same as above, with a chainable builder API |
Custom node types are **namespaced** (e.g., `"mylib:code-editor"`) to prevent conflicts. Resolve `fd` with `getInstance()` inside the component tree, or use the mount handle's `.instance` outside it. You can register before or after mounting.
`BaseRegistry` tracks a version counter that invalidates dependent `$derived`
reads. When you register a node after mount, the counter bumps and the editor
re-resolves, so late registrations take effect.
## Quick start
**1. Write a Svelte component:**
```svelte
{data.label}
{data.config?.code ?? ''}
```
**2. Register it:**
```typescript
import { getInstance } from '@flowdrop/flowdrop/editor';
import CodeEditorNode from './CodeEditorNode.svelte';
const fd = getInstance(); // or app.instance outside the component tree
fd.nodes.registerCustom('myapp:code-editor', 'Code Editor', CodeEditorNode, {
icon: 'mdi:code-braces',
description: 'A custom code editor node',
category: 'custom'
});
```
**3. Make it available in the sidebar** by passing `NodeMetadata` with a matching `type`:
```typescript
const app = await mountFlowDropApp(container, {
nodes: [
{
id: 'myapp:code-editor',
name: 'Code Editor',
type: 'myapp:code-editor', // Must match registered type
description: 'Write and edit code',
category: 'processing',
inputs: [{ id: 'input', name: 'Input', type: 'input', dataType: 'string' }],
outputs: [{ id: 'output', name: 'Output', type: 'output', dataType: 'string' }]
}
]
});
```
## NodeComponentProps
All custom node components must accept:
```typescript
interface NodeComponentProps {
id: string; // node instance id, passed by SvelteFlow
data: {
label: string;
config: Record;
metadata: NodeMetadata;
executionInfo?: NodeExecutionInfo;
onConfigOpen?: (node) => void;
};
selected?: boolean;
isProcessing?: boolean;
isError?: boolean;
}
```
## Plugin registration
Register multiple nodes under a shared namespace:
```typescript
import { getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
const result = fd.nodes.registerPlugin({
namespace: 'awesome',
name: 'Awesome Nodes',
version: '1.0.0',
nodes: [
{
type: 'fancy',
displayName: 'Fancy Node',
component: FancyNode,
icon: 'mdi:sparkles'
},
{
type: 'glow',
displayName: 'Glowing Node',
component: GlowNode,
icon: 'mdi:lightbulb'
}
]
});
// result.registeredTypes: ["awesome:fancy", "awesome:glow"]
```
### Fluent builder
```typescript
import { createPlugin, getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
createPlugin('awesome', 'Awesome Nodes')
.version('1.0.0')
.node('fancy', 'Fancy Node', FancyNode, { icon: 'mdi:sparkles' })
.node('glow', 'Glowing Node', GlowNode, { icon: 'mdi:lightbulb' })
.register(fd.nodes);
```
## Plugin management
Plugin lifecycle is managed on `fd.nodes`; `isValidNamespace` remains a standalone helper:
```typescript
import { isValidNamespace, getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
fd.nodes.unregisterPlugin('awesome'); // Remove all nodes from a plugin
fd.nodes.getRegisteredPlugins(); // List registered namespaces
fd.nodes.getPluginNodeCount('awesome'); // Count nodes in a plugin
isValidNamespace('my-lib'); // Validate namespace format
```
Namespace rules: Must match `/^[a-z][a-z0-9-]*$/` — lowercase letters, digits, and hyphens, starting with a letter.
## Built-in node types
If no custom component is registered for a `type`, FlowDrop falls back to built-in types:
| Type | Description |
| -------------- | -------------------------------------- |
| `workflowNode` | Full-featured node with inputs/outputs |
| `simple` | Compact layout |
| `square` | Minimal icon-only design |
| `tool` | Agent tool nodes |
| `gateway` | Branching control flow |
| `note` | Markdown sticky notes |
| `terminal` | Circular start/end nodes |
Use `supportedTypes` on `NodeMetadata` to let users switch between visual types at runtime.