This page documents the Zustand-based client-side state management layer for the Langflow frontend. It covers each store's purpose, the data it owns, and how stores interact with each other.
For the visual flow canvas that reads this state, see page 5.2. For how the build process writes to this state, see page 5.6. For the API layer that syncs state to the backend, see page 5.7.
All frontend state is managed with Zustand Each slice of state lives in an independent create() store, exported as a custom hook. Components subscribe to individual store slices using selector functions, preventing unnecessary re-renders.
Store registry:
| Hook | File | Primary Concern |
|---|---|---|
useFlowStore | src/frontend/src/stores/flowStore.ts | Active flow: nodes, edges, build state, flow pool |
useFlowsManagerStore | src/frontend/src/stores/flowsManagerStore.ts | Flow list, current flow ID, undo/redo history |
messagesStore | src/frontend/src/stores/messagesStore.ts | Chat messages for the playground |
useTypesStore | src/frontend/src/stores/typesStore.ts | Component type definitions and templates |
useGlobalVariablesStore | src/frontend/src/stores/globalVariablesStore/globalVariables.ts | Global variable entries and field mappings |
useShortcutsStore | src/frontend/src/stores/shortcuts.ts | Keyboard shortcut bindings |
useAlertStore | src/frontend/src/stores/alertStore.ts | Toast notifications (error, success, notice) |
useDarkStore | src/frontend/src/stores/darkStore.ts | Dark mode toggle, Langflow version string |
useStoreStore | src/frontend/src/stores/storeStore.ts | Component marketplace authentication state |
useTweaksStore | src/frontend/src/stores/tweaksStore.ts | Per-node input value overrides (tweaks) |
useUtilityStore | src/frontend/src/stores/utilityStore.ts | Shared utility state (e.g., available tags) |
Sources: src/frontend/src/stores/flowStore.ts1-65 src/frontend/src/stores/flowsManagerStore.ts1-20 src/frontend/src/stores/messagesStore.ts1-10 src/frontend/src/stores/typesStore.ts1-15 src/frontend/src/stores/shortcuts.ts1-10
Store dependency map
Sources: src/frontend/src/stores/flowStore.ts56-62 src/frontend/src/stores/flowsManagerStore.ts8-10
useFlowStoreFile: src/frontend/src/stores/flowStore.ts
Type definition: src/frontend/src/types/zustand/flow/index.ts
This is the most complex store. It owns the state of the currently open flow, including the ReactFlow canvas data and build execution status.
| Property | Type | Description |
|---|---|---|
nodes | AllNodeType[] | ReactFlow nodes for the active flow |
edges | EdgeType[] | ReactFlow edges for the active flow |
currentFlow | FlowType | undefined | The full FlowType object of the open flow |
reactFlowInstance | ReactFlowInstance | null | The live ReactFlow API handle |
isBuilding | boolean | True while a build is running |
buildStartTime | number | null | Unix timestamp when current build began |
buildDuration | number | null | Duration of last completed build |
buildingFlowId | string | null | ID of the flow being built |
buildingSessionId | string | null | Session ID for the current build |
isPending | boolean | True before first build completes |
flowPool | FlowPoolType | Per-node build result history { [nodeId]: VertexBuildTypeAPI[] } |
flowBuildStatus | Record<string, BuildStatus> | Per-node build status enum |
flowState | FlowState | undefined | Input/output key metadata for the flow |
inputs / outputs | Array<{type, id, displayName}> | Detected I/O nodes in the flow |
hasIO | boolean | True if the flow has at least one I/O node |
componentsToUpdate | ComponentsToUpdateType[] | Nodes with outdated component code |
dismissedNodes | string[] | Node IDs whose update banners have been dismissed |
lastCopiedSelection | OnSelectionChangeParams | null | Clipboard for copy/paste |
autoSaveFlow | ((flow?) => void) | undefined | Debounced save callback, injected by useAutoSaveFlow |
helperLineEnabled | boolean | Whether alignment helper lines are active |
rightClickedNodeId | string | null | ID of the node currently right-clicked |
Sources: src/frontend/src/types/zustand/flow/index.ts64-240 src/frontend/src/stores/flowStore.ts65-130
| Action | Description |
|---|---|
setNodes(change) | Replaces nodes, runs cleanEdges, recalculates I/O, triggers auto-save |
setEdges(change) | Replaces edges, triggers auto-save |
setNode(id, change) | Updates a single node; unfreezes it if a user change is detected |
deleteNode(nodeId) | Removes node(s) by ID, cleans up edges |
deleteEdge(edgeId) | Removes edge(s) by ID |
onNodesChange(changes) | Applies ReactFlow NodeChange[] with applyNodeChanges |
onEdgesChange(changes) | Applies ReactFlow EdgeChange[] with applyEdgeChanges |
onConnect(params) | Adds a new edge via addEdge, validates connection |
paste(selection, position) | Pastes copied nodes/edges at a position, generates new IDs |
resetFlow(flow) | Replaces the entire canvas with a new flow, calls cleanEdges, resets build state |
updateCurrentFlow(partial) | Writes partial node/edge updates into currentFlow |
setIsBuilding(bool) | Sets build state, resets timing fields on start |
addDataToFlowPool(data, nodeId) | Appends a VertexBuildTypeAPI result to flowPool[nodeId] |
updateEdgesRunningByNodes(ids, bool) | Marks edges as animated/running during a build |
updateFreezeStatus(nodeIds, freeze) | Sets frozen flag on nodes |
stopBuilding() | Aborts the build controller and resets build state |
Sources: src/frontend/src/stores/flowStore.ts296-500
resetFlow — Flow InitializationWhen navigating to a different flow, resetFlow is the primary entry point. It:
cleanEdges to strip invalid edges.inputs and outputs via getInputsAndOutputs.updateComponentsToUpdate to detect outdated components.localStorage keyed on dismiss_{flowId}.useTweaksStore.getState().initialSetup.nodes, edges, currentFlow, and resets flowPool and flowBuildStatus.Sources: src/frontend/src/stores/flowStore.ts221-259
FlowPoolType StructureflowPool accumulates build results for each node in the current build session.
Sources: src/frontend/src/types/zustand/flow/index.ts51-53 src/frontend/src/types/api/index.ts218-231
useFlowsManagerStoreFile: src/frontend/src/stores/flowsManagerStore.ts
Type definition: src/frontend/src/types/zustand/flowsManager/index.ts
Owns the list of all flows and manages which flow is currently open. Also implements undo/redo history.
| Property | Type | Description |
|---|---|---|
flows | FlowType[] | All flows visible to the current user |
currentFlowId | string | ID of the currently open flow |
examples | FlowType[] | Starter/example flows |
autoSaving | boolean | Whether auto-save is enabled |
autoSavingInterval | number | Debounce interval in ms (SAVE_DEBOUNCE_TIME) |
IOModalOpen | boolean | Whether the chat/playground modal is open |
healthCheckMaxRetries | number | Max backend health check retries |
Sources: src/frontend/src/types/zustand/flowsManager/index.ts1-50 src/frontend/src/stores/flowsManagerStore.ts19-50
The undo/redo mechanism uses two module-level plain objects — past and future — keyed by flow ID. This keeps history out of the reactive store to avoid serialization overhead.
Undo/redo data flow
takeSnapshot() deep-clones the current nodes and edges from useFlowStore and pushes them onto past[currentFlowId].undo() pops the last entry from past[currentFlowId], pushes the current state to future[currentFlowId], and calls setNodes/setEdges on useFlowStore.redo() reverses the operation.maxHistorySize: 100 entries per flow.Sources: src/frontend/src/stores/flowsManagerStore.ts11-17 src/frontend/src/stores/flowsManagerStore.ts60-140
messagesStoreFile: src/frontend/src/stores/messagesStore.ts
Stores the list of ChatMessageType objects displayed in the playground chat panel. Messages are appended when SSE build events arrive carrying chat output, and cleared when a new session starts.
Key state:
messages: ChatMessageType[]setMessages(messages) — replaces entire listaddMessage(message) — appends a single messageupdateMessage(message) — replaces a message by session + idremoveMessages(ids) — removes messages by ID arrayclearMessages() — empties the listsetGetMessagesQuery(fn) — stores a reference to the React Query refetch function for the messages APISources: src/frontend/src/stores/messagesStore.ts1-80
useTypesStoreFile: src/frontend/src/stores/typesStore.ts
Holds the component type catalog fetched from the backend at startup (GET /api/v1/all).
| Property | Type | Description |
|---|---|---|
types | { [key: string]: string } | Maps component type names to their category |
templates | { [key: string]: APIClassType } | Full component template definitions, keyed by type name |
data | APIDataType | Raw response from /api/v1/all |
setTypes(types) | action | Replaces types |
setTemplates(templates) | action | Replaces templates |
setData(data) | action | Replaces data |
useFlowStore.updateComponentsToUpdate reads useTypesStore.getState().templates to compare a node's embedded code against the canonical template to detect stale components.
Sources: src/frontend/src/stores/typesStore.ts1-40 src/frontend/src/stores/flowStore.ts96-113
useGlobalVariablesStoreFile: src/frontend/src/stores/globalVariablesStore/globalVariables.ts
Type: src/frontend/src/types/zustand/globalVariables/index.ts
Manages global variables that can be referenced in component fields across any flow.
| Property | Type | Description |
|---|---|---|
globalVariablesEntries | string[] | undefined | Names of all defined global variables |
unavailableFields | { [name: string]: string } | Variable names mapped to the field types they cannot be used in |
setGlobalVariablesEntries(entries) | action | Sets the variable name list |
setUnavailableFields(fields) | action | Sets field restrictions |
Global variables are loaded via the useGetGlobalVariables React Query hook and stored here so any component input field can enumerate them.
Sources: src/frontend/src/types/zustand/globalVariables/index.ts1-15
useShortcutsStoreFile: src/frontend/src/stores/shortcuts.ts
Type: src/frontend/src/types/store/index.ts (shortcutsStoreType)
Stores the current keyboard shortcut bindings. Individual shortcut strings are exposed as named properties so components can subscribe to just the shortcuts they need.
defaultShortcuts in src/frontend/src/constants/constants.ts.setShortcuts(shortcuts) replaces the bindings and simultaneously updates each named property using toCamelCase(shortcut.name).useHotkeys from react-hotkeys-hook is called throughout the app with values from this store — e.g. useHotkeys(undoAction, handleUndo) in PageComponent.Sources: src/frontend/src/stores/shortcuts.ts1-50 src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx350-383
| Store | File | Key State |
|---|---|---|
useAlertStore | src/frontend/src/stores/alertStore.ts | errorData, successData, noticeData — each a {title, list?} object; set by setErrorData, setSuccessData, setNoticeData |
useDarkStore | src/frontend/src/stores/darkStore.ts | dark: boolean, version: string; version is used when creating flow components |
useStoreStore | src/frontend/src/stores/storeStore.ts | hasStore, hasApiKey, validApiKey — controls marketplace-related UI affordances |
useTweaksStore | src/frontend/src/stores/tweaksStore.ts | Per-node input value overrides; initialized by flowStore.resetFlow via initialSetup(nodes, flowId) |
useUtilityStore | src/frontend/src/stores/utilityStore.ts | tags: Tag[] — tag list for the component marketplace |
Sources: src/frontend/src/stores/flowStore.ts56-62 src/frontend/src/modals/shareModal/index.tsx62 src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx72-76
Cross-store read/write map
Key patterns:
useFlowStore directly calls useFlowsManagerStore.getState() to get currentFlowId during updateCurrentFlow.useFlowsManagerStore.takeSnapshot calls useFlowStore.getState() to snapshot nodes and edges.useFlowStore.updateComponentsToUpdate calls useTypesStore.getState().templates to compare node code.flowStore.resetFlow calls useTweaksStore.getState().initialSetup.useAlertStore.getState().setErrorData.Sources: src/frontend/src/stores/flowStore.ts56-62 src/frontend/src/stores/flowStore.ts96-113 src/frontend/src/stores/flowStore.ts221-259 src/frontend/src/stores/flowsManagerStore.ts60-140
Components subscribe to store slices using the selector pattern. The useShallow utility from zustand/react/shallow is used for object selectors to prevent unnecessary re-renders.
Single scalar value:
const isBuilding = useFlowStore((state) => state.isBuilding);
Object selector with shallow equality:
const { hasStore, hasApiKey } = useStoreStore(
useShallow((state) => ({ hasStore: state.hasStore, hasApiKey: state.hasApiKey }))
);
Derived selector (find in array):
const componentUpdate = useFlowStore(
useShallow((state) =>
state.componentsToUpdate.find((c) => c.id === data.id)
)
);
Sources: src/frontend/src/CustomNodes/GenericNode/index.tsx80-129 src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx72-76
Auto-save is not implemented inside flowStore directly. Instead, useAutoSaveFlow (a custom hook) creates a debounced save function and injects it into flowStore via:
useFlowStore.setState({ autoSaveFlow });
See src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx226-228 After this, any action that calls setNodes, setEdges, or setNode will automatically trigger autoSaveFlow() if it is defined. This allows flowStore to remain decoupled from the API client while still ensuring saves happen on every user mutation.
Sources: src/frontend/src/stores/flowStore.ts306-381 src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx226-228
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.