--- 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