---
title: "Architecture overview"
description: "How FlowDrop's modules, components, stores, and services fit together."
source: https://flowdrop.io/docs/concepts/architecture-overview
site: FlowDrop documentation
---
# Architecture overview
This page explains how FlowDrop is structured internally, so you can make
informed decisions about what to import, how to integrate, and where to extend.
## High-level architecture
FlowDrop is a **frontend library** that communicates with **your backend** via REST.
```
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
Browser
│ │
┌─────────────────────┐
│ │ FlowDrop │ │
├─────────────────────┤ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
│ │User Interface │ │ Your Backend
│ │ │ │ │
│ │ ├─╼ Navbar │ │ ┌────────────────────────┐
│ ├─╼ Canvas │ │ │ Python/PHP/NodeJS │ │
│ │ ╰─╼ Config Panel │ │ │ Framework │
│ │ │ ├────────────────────────┤ │
│ ├─────────────────────┤ │ │Storage and Business │
│Browser Storage │ REST │ │Logic │ │
│ │ │ │ │───API───▶ │ │ │
│ ├─╼ Workflow │ │ │ ├─╼ Nodes │ │
│ │ ├─╼ History │ │ │ ├─╼ Workflows │
│ ╰─╼ Settings │ │ │ ├─╼ Access │ │
│ │ │ │ │ ├─╼ Persistant Storage │
├─────────────────────┤ │ │ ╰─╼ Execution │ │
│ │Services │ │ │ │
│ │ │ │ │ │ │
│ │ ├─╼ API Client │ │ └────────────────────────┘
│ ├─╼ Drafts │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
│ │ ╰─╼ Toasts │ │
│ │
│ └─────────────────────┘ │
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
```
## Module structure
FlowDrop is tree-shakable. Each sub-module has different dependencies and bundle cost:
| Module | What it provides | Heavy deps |
| ---------------------------------- | ------------------------------------------------ | ------------------- |
| `@flowdrop/flowdrop/core` | Types, utilities, auth providers, config helpers | None |
| `@flowdrop/flowdrop/editor` | WorkflowEditor, mount functions, node components | @xyflow/svelte |
| `@flowdrop/flowdrop/form` | SchemaForm, field components | None |
| `@flowdrop/flowdrop/form/code` | Code & template editors | CodeMirror (~300KB) |
| `@flowdrop/flowdrop/form/markdown` | Markdown editor | CodeMirror |
| `@flowdrop/flowdrop/display` | MarkdownDisplay | marked |
| `@flowdrop/flowdrop/playground` | Playground, chat, interrupts | Editor + Form |
| `@flowdrop/flowdrop/settings` | Settings panel, theme toggle | Form |
| `@flowdrop/flowdrop/styles` | CSS design tokens | None |
| `@flowdrop/flowdrop` | Bootstrap front door (App, mount, instances) | Bootstrap surface |
## Component hierarchy
When you mount `mountFlowDropApp()`, this is the component tree:
```text
App
├── Navbar
│ ├── Logo
│ ├── WorkflowName (editable)
│ ├── Save / Export buttons
│ ├── Custom NavbarActions
│ └── ThemeToggle / Settings
├── NodeSidebar
│ ├── Search
│ └── CategoryGroups
│ └── NodeCards (draggable)
├── WorkflowEditor (@xyflow/svelte canvas)
│ ├── Nodes (WorkflowNode, SimpleNode, GatewayNode, etc.)
│ │ └── Ports (input/output handles)
│ ├── Edges (styled by category)
│ └── ConnectionLine
├── ConfigPanel (right side, on node click)
│ ├── NodeHeader (name, type, icon)
│ └── SchemaForm (generated from configSchema)
│ └── FormFields (text, select, code, template, etc.)
└── ToastContainer
```
`mountWorkflowEditor()` mounts just the canvas — no navbar, no sidebar.
Each mount produces one such tree backed by its own instance; node/field
registries and settings are shared across all trees on the page.
## Stores
FlowDrop uses **Svelte 5 runes** for state management. Each mount creates a
per-instance `FlowDropInstance` container that holds these stores:
| Store | Purpose | Key state |
| ----------------------- | ---------------------- | ------------------------------------------- |
| **workflowStore** | Central workflow state | nodes, edges, metadata, isDirty |
| **historyStore** | Undo/redo | past states, future states, canUndo/canRedo |
| **settingsStore** | User preferences | theme, editor behavior, UI config |
| **playgroundStore** | Playground sessions | sessions, messages, isExecuting |
| **interruptStore** | Human-in-the-loop | pending/resolved interrupts |
| **categoriesStore** | Node categories | category definitions, colors |
| **portCoordinateStore** | Handle positions | port coordinates for edge rendering |
### Instance model
Every mount creates an isolated `FlowDropInstance` container holding the stores
above (workflow, history, playground, interrupts, categories, port coordinates,
and pipeline-panel state), resolved through Svelte context. Multiple editors can
therefore coexist on one page without sharing state.
See the [multiple instances guide](/editor/multiple-instances) for details.
## Services
Services handle communication and side effects:
| Service | Purpose |
| ---------------------- | ----------------------------------------------------------- |
| **API client** | HTTP requests to your backend (nodes, workflows, execution) |
| **Draft storage** | Auto-save to localStorage |
| **Toast service** | Success/error/loading notifications |
| **Dynamic schema** | Fetch config schemas from API at runtime |
| **Playground service** | Manage sessions, poll for messages |
| **Interrupt service** | Submit interrupt resolutions |
| **History service** | Track and replay state changes |
| **Settings service** | Load/save preferences (localStorage + API) |
## Data flow
Here's what happens when a user makes a change:
```
┌───────────────────────┐
│ User action │
│ (drag node, edit │
│ config, draw edge) │
└───────────────────────┘
│
▼
┌───────────────────────┐
│Component event handler│
└───────────────────────┘
│
│
▼
┌───────────────────────┐
│ workflowStore update │
│ (state mutation) │
└───────────────────────┘
│
│ ┌────────────────────────────┐
│ │ historyStore │
├──────▶│ records snapshot │
│ │ (for undo) │
│ └────────────────────────────┘
│ ┌────────────────────────────┐
│ │ isDirty │
├──────▶│ flag set to true │
│ │ │
│ └────────────────────────────┘
│ ┌────────────────────────────┐
│ │ │
├──────▶│ UI re-renders │
│ │ │
│ └────────────────────────────┘
│ ┌────────────────────────────┐
│ │ │
│ │ onWorkflowChange(workflow, │
│ │ changeType) │
│ │ │
├──────▶│ │
│ │ your callback — analytics, │
│ │ validation, etc. │
│ │ │
│ └────────────────────────────┘
│ ┌────────────────────────────┐
│ │ onDirtyStateChange(true) │
│ │ │
└──────▶│your callback — update save │
│ button, etc. │
│ │
└────────────────────────────┘
```
When the user saves:
```
┌─────────────────────┐
│ User clicks Save │
└─────────────────────┘
│
▼
┌───────────────────────────┐
│ onBeforeSave(workflow) │
└───────────────────────────┘
│
│
┌──False──────┴──────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ │ │ API client: │
│ Cancel │ │ │
│ │ │ PUT /workflows/{id} │
└─────────────────────┘ └─────────────────────┘
│
│
│
┌─────Success─────────────┴───Error─┐
│ │
│ │
▼ ▼
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃isDirty = false, draft cleared┃ ┃ Toast notification ┃
┃ ┃ ┃ ┃
┣──────────────────────────────┫ ┣──────────────────────────────┫
│ onAfterSave(workflow) │ │ onSaveError(error, workflow) │
└──────────────────────────────┘ ├──────────────────────────────┤
│ onApiError(error, 'save') │
└──────────────────────────────┘
```
## Registry system
FlowDrop has two registries for extending the editor:
### Node component registry
Register custom Svelte components for new node types against the instance's
`fd.nodes` registry:
```typescript
import { getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
fd.nodes.registerCustom('my-custom-node', 'My Custom Node', MyNodeComponent);
```
### Field component registry
Register custom form fields for config schemas against `fd.fields`:
```typescript
import { getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
fd.fields.register('my-field', {
component: MyFieldComponent,
matcher: (schema) => schema.format === 'my-field',
priority: 10
});
```
Both registries are **instance-scoped** — seeded with builtins in the instance
constructor and resolved via `getInstance()`. You can register after mounting.
`BaseRegistry` tracks a version counter that invalidates dependent `$derived`
reads, so registrations made after mount still take effect.
## Next steps
- [What is a Workflow?](/concepts/what-is-a-workflow) — the mental model
- [Quick Start](/start/quickstart) — mount FlowDrop in your app
- [Backend Implementation](/editor/integration/backend-implementation) — build the API FlowDrop expects
- [Event System](/editor/advanced/event-system) — hook into every lifecycle event