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