---
title: "Multiple instances"
description: "Run several isolated FlowDrop editors or playgrounds on a single page."
source: https://flowdrop.io/docs/editor/multiple-instances
site: FlowDrop documentation
---
# Multiple instances
FlowDrop supports multiple editor instances on one page. Each mount gets its own
**state container** — workflow data, undo/redo history, playground sessions,
interrupts, and panel state are fully isolated between instances. Editing,
deleting, or undoing in one editor never affects another, and destroying one
leaves its siblings working.
## Quick start: two editors via the mount API
```typescript
import { mountFlowDropApp } from '@flowdrop/flowdrop/editor';
const left = await mountFlowDropApp(document.getElementById('editor-left'), {
workflow: workflowA,
nodes: nodeTypes,
instanceId: 'left' // scopes draft/panel storage keys
});
const right = await mountFlowDropApp(document.getElementById('editor-right'), {
workflow: workflowB,
nodes: nodeTypes,
instanceId: 'right'
});
// Each handle controls only its own editor:
left.isDirty(); // false
right.getWorkflow(); // workflowB
left.destroy(); // `right` keeps working
```
## Quick start: two editors in Svelte
Create an instance per editor with `createFlowDropInstance()` and pass it via
the `instance` prop:
```svelte
```
`WorkflowEditor`, `Playground`, `PlaygroundStudio`, `PlaygroundModal`, and
`PlaygroundApp` accept the same `instance` prop.
## The default instance
You only need `instanceId` when mounting **more than one** editor. The first
mount without an `instanceId` becomes the **page-default instance**, which is
what `getInstance()` resolves to for single-editor embeds with no explicit
provider.
Instances are the API: there are no module-level store singletons. Resolve the
owning instance with `getInstance()` inside the component tree, or hold the
mount handle's `.instance` outside it. Each instance keeps its own scoped
localStorage keys (`flowdrop:draft:default:`,
`fd-pipeline-panel-open:default` for the default instance).
Additional mounts without an explicit id get auto-generated ones (`fd-1`,
`fd-2`, …). Prefer explicit ids whenever drafts are enabled, so each editor's
drafts land under a stable, predictable key.
## Instance-scoped storage keys
| State | Default instance | Instance with `instanceId: 'left'` |
| ------------------- | ------------------------------------- | ---------------------------------- |
| Workflow drafts | `flowdrop:draft:default:` | `flowdrop:draft:left:` |
| Pipeline panel open | `fd-pipeline-panel-open:default` | `fd-pipeline-panel-open:left` |
| Pipeline view mode | `fd-pipeline-view-mode:default` | `fd-pipeline-view-mode:left` |
`clearAllDrafts()` sweeps everything under `flowdrop:draft:` — instance
sub-namespaces included — so a logout handler still clears all editors at once.
## Accessing instance state programmatically
Inside FlowDrop's component tree, resolve the current instance with
`getInstance()` (during component init):
```svelte
```
Outside the tree, hold on to the container you created (or the mount handle).
The `FlowDropInstance` exposes `workflow`, `history`, `historyBindings`,
`playground`, `interrupts`, `categories`, `portCoordinates`, `pipelinePanel`,
and `destroy()`.
## What stays page-global (by design)
Some state is deliberately shared across all instances on a page:
- **Theme and settings** — one `data-theme` and one settings store per page.
This includes UI toggles like console-open, sidebar-collapsed, and the
bottom-panel tab: toggling them in one editor affects all editors.
- **Port-compatibility config** — each instance owns a `PortCompatibilityChecker`
at `fd.portCompatibility`, re-initialized by mount from the backend's port
config; the last mount's fetched config wins for shared backends.
- **API endpoint config** — each instance owns an `ApiContext` at `fd.api`,
configured by mount via `fd.api.configure(config, authProvider)`.
- **Playground live polling** — playground session/message _state_ is isolated
per instance, but the polling timer is page-global: only one playground
actively polls at a time. If two playgrounds need concurrent live updates,
push responses yourself via the mount handle's `pushMessages()` with your own
transport (WebSocket/SSE).
## SSR (SvelteKit)
Server rendering works without any extra setup. During SSR, the provider
components (`App`, `WorkflowEditor`, …) create a fresh per-render instance
automatically.
The page-default instance is **browser-only** — module-level mutable state on
the server would leak between requests. So FlowDrop gives each render its own
instance. Resolving the default instance (e.g. via `getInstance()`) during SSR
outside a FlowDrop component tree throws with an explanatory error instead of
leaking state.
## Troubleshooting
**Two editors share state** — two un-keyed mounts both claimed the default
instance. Pass explicit `instanceId`s and resolve state via `getInstance()` /
the mount handle's `.instance`.
**Drafts collide between editors** — both mounts omitted `instanceId`, so the
second got an auto-generated id that changes across reloads. Pass stable
explicit ids.