---
title: "Performance"
description: "Bundle size, lazy loading, SSR guard patterns, and tips for large workflows in FlowDrop."
source: https://flowdrop.io/docs/editor/performance
site: FlowDrop documentation
---
# Performance
FlowDrop's editor is a rich component with many dependencies. This guide covers strategies to minimize bundle impact and ensure smooth performance at scale.
## Bundle sizes
Approximate gzip sizes by entry point:
| Entry Point | Approx. gzip size | Notes |
| ---------------------------------- | ----------------- | ----------------------------------------- |
| `@flowdrop/flowdrop/core` | ~10 KB | Types and utilities only — no heavy deps |
| `@flowdrop/flowdrop/editor` | ~180 KB | Includes `@xyflow/svelte`, Svelte runtime |
| `@flowdrop/flowdrop/form` | ~25 KB | Form fields without CodeMirror |
| `@flowdrop/flowdrop/form/code` | ~350 KB | Includes CodeMirror and language packs |
| `@flowdrop/flowdrop/form/markdown` | ~300 KB | Includes CodeMirror markdown mode |
| `@flowdrop/flowdrop/playground` | ~200 KB | Editor + session management |
| `@flowdrop/flowdrop` | ~400 KB | Full bundle (avoid in production) |
Use specific entry points rather than `@flowdrop/flowdrop` to tree-shake unused modules.
## Lazy loading the editor
The editor bundle is large. Load it only when the user navigates to the editor page:
```javascript
// Vanilla JS — dynamic import
async function mountEditor(container) {
const [{ mountFlowDropApp }, { createEndpointConfig }] = await Promise.all([
import('@flowdrop/flowdrop/editor'),
import('@flowdrop/flowdrop/core')
]);
await import('@flowdrop/flowdrop/styles');
return mountFlowDropApp(container, {
endpointConfig: createEndpointConfig('/api/flowdrop')
});
}
```
### React
```jsx
import React, { Suspense, lazy } from 'react';
const FlowDropEditor = lazy(() => import('./FlowDropEditor'));
export function EditorPage() {
return (
Loading editor...}>
);
}
```
Where `FlowDropEditor` is a wrapper component that calls `mountFlowDropApp` in a `useEffect`.
## Deferring CodeMirror
If you use code or markdown fields but not on every page, load them on demand:
```javascript
async function mountEditorWithCodeFields(container, endpointConfig) {
// Load form fields that require CodeMirror only when needed
const [{ mountFlowDropApp }, { createEndpointConfig }] = await Promise.all([
import('@flowdrop/flowdrop/editor'),
import('@flowdrop/flowdrop/core')
]);
// This registers code/markdown fields into the registry
await import('@flowdrop/flowdrop/form/code');
await import('@flowdrop/flowdrop/form/markdown');
return mountFlowDropApp(container, { endpointConfig });
}
```
## SSR guard patterns
FlowDrop accesses `window`, `document`, and browser APIs — it cannot run on the server. Always guard your mount calls.
### SvelteKit
```javascript
import { browser } from '$app/environment';
import { onMount } from 'svelte';
let app;
onMount(async () => {
if (!browser) return;
const { mountFlowDropApp } = await import('@flowdrop/flowdrop/editor');
app = await mountFlowDropApp(document.getElementById('editor'), { ... });
return () => app?.destroy();
});
```
### Next.js (App Router)
```javascript
'use client';
import dynamic from 'next/dynamic';
const FlowDropEditor = dynamic(() => import('../components/FlowDropEditor'), { ssr: false });
```
### Nuxt
```html
```
### Vite `optimizeDeps`
If you see `Failed to resolve import` errors during development, exclude FlowDrop from Vite's pre-bundling:
```javascript
// vite.config.ts
export default defineConfig({
optimizeDeps: {
exclude: ['@flowdrop/flowdrop', '@xyflow/svelte']
}
});
```
See the [Installation guide](/start/quickstart) for more setup tips.
## Large workflow performance
For workflows with many nodes (50+):
### Use batch updates
```javascript
const { actions } = app.instance.workflow;
// Apply nodes and edges in a single reactive update
actions.batchUpdate({
nodes: [...existingNodes, nodeA, nodeB],
edges: [...existingEdges, edge]
});
```
### Use history transactions
Group related changes into a single undo step:
```javascript
import { getInstance } from '@flowdrop/flowdrop/editor';
const fd = getInstance();
fd.historyBindings.startTransaction(fd.workflow.current, 'Bulk update');
// ... multiple changes
fd.historyBindings.commitTransaction();
```
### Disable auto-save for programmatic updates
When making many changes programmatically, temporarily disable auto-save:
```javascript
await mountFlowDropApp(container, {
endpointConfig,
features: {
autoSaveDraft: false, // disable localStorage auto-save
showToasts: false // disable toast notifications
}
});
```
See [Mount API](/editor/reference/mount-api) for the full `features` options.