This page provides an architectural overview of the n8n frontend application. It covers the package layout, plugin registration, component hierarchy, state management, and the major UI subsystems. Detailed treatment of individual subsystems is in the child pages:
The frontend is a Vue 3 Single-Page Application (SPA) served as a static bundle by the n8n backend.
| Technology | Role |
|---|---|
| Vue 3 (Composition API) | Component framework |
| Pinia | State management |
| Vue Router | Client-side routing |
VueFlow (@vue-flow/core) | Directed-graph canvas for workflow editing |
| Element Plus | Base UI primitives (dialogs, dropdowns, forms) |
| CodeMirror 6 | Code and expression editors |
| PostHog | Feature flags and session analytics |
| Sentry | Error monitoring |
Diagram: Frontend Package Dependencies
Sources: packages/frontend/editor-ui/src/main.ts1-61
The application is bootstrapped in packages/frontend/editor-ui/src/main.ts. The Vue app is created and several plugins are registered before mounting.
Registered plugins (in order):
| Plugin | File | Responsibility |
|---|---|---|
SentryPlugin | src/app/plugins/sentry | Sentry error tracking |
TelemetryPlugin | src/app/plugins/telemetry | PostHog + analytics |
PiniaVuePlugin | pinia | State management |
GlobalComponentsPlugin | src/app/plugins/components | Registers global Vue components |
GlobalDirectivesPlugin | src/app/plugins/directives | Registers custom Vue directives |
pinia instance | ā | Store container |
router | src/app/router | Vue Router |
i18nInstance | @n8n/i18n | Translations |
ChartJSPlugin | src/app/plugins/chartjs | Chart.js for insights |
Module routes are registered via registerModuleRoutes(router) before any plugin registration, so navigating directly to a module URL works.
Sources: packages/frontend/editor-ui/src/main.ts1-61
Diagram: Core Component Tree
Sources: packages/frontend/editor-ui/src/app/views/NodeView.vue1-160 packages/frontend/editor-ui/src/features/workflows/canvas/components/Canvas.vue1-165 packages/frontend/editor-ui/src/features/workflows/canvas/components/elements/nodes/CanvasNode.vue1-60
The canvas uses the VueFlow library (@vue-flow/core) and is organized around these primary files:
| File | Role |
|---|---|
NodeView.vue | Top-level view; coordinates all canvas events, stores, and data loading |
WorkflowCanvas.vue | Thin wrapper that provides workflow data to Canvas.vue |
Canvas.vue | Core VueFlow integration: panning, selection, key bindings, node/edge event dispatch |
CanvasNode.vue | Per-node Vue component registered as a VueFlow custom node type |
CanvasNodeDefault.vue | Renders the standard node shape (icon, status icons, handles) |
useCanvasMapping.ts | Composable that maps INodeUi[] + IConnections ā CanvasNode[] + CanvasConnection[] |
useCanvasOperations.ts | Composable that implements add, move, rename, delete, connect, duplicate, and paste for nodes |
Canvas node render types are declared in canvas.types.ts as CanvasNodeRenderType:
| Render type | Enum value | Used for |
|---|---|---|
Default | "default" | Standard integration nodes |
StickyNote | "n8n-nodes-base.stickyNote" | Sticky note nodes |
AddNodes | "n8n-nodes-internal.addNodes" | Empty-canvas placeholder |
ChoicePrompt | "n8n-nodes-internal.choicePrompt" | Human-in-the-loop prompt |
Sources: packages/frontend/editor-ui/src/features/workflows/canvas/canvas.types.ts44-50 packages/frontend/editor-ui/src/features/workflows/canvas/composables/useCanvasMapping.ts71-170
The NDV panel opens when a user double-clicks a node. It is lazy-loaded:
LazyNodeDetailsView ā import('@/features/ndv/shared/views/NodeDetailsView.vue')
LazyNodeDetailsViewV2 ā import('@/features/ndv/shared/views/NodeDetailsViewV2.vue')
The active node is tracked in useNDVStore (ndv.store). The NDV contains parameter input components for editing node configuration and data output tables for inspecting results.
Sources: packages/frontend/editor-ui/src/app/views/NodeView.vue152-158
All shared reactive state lives in Pinia stores. The stores referenced throughout NodeView.vue show the full set used by the main editor:
Diagram: NodeView Store Dependencies
Sources: packages/frontend/editor-ui/src/app/views/NodeView.vue181-205
The AI builder sidebar is rendered by AskAssistantBuild.vue. Its state lives in builder.store.ts (a Pinia store identified by STORES.BUILDER).
Key state in useBuilderStore:
| Property | Type | Purpose |
|---|---|---|
chatMessages | ChatUI.AssistantMessage[] | Full chat history |
streaming | boolean | Whether AI is currently generating |
builderThinkingMessage | string | undefined | "Thinkingā¦" indicator text |
initialGeneration | boolean | True during the first workflow generation |
builderMode | 'build' | 'plan' | Current mode (build immediately or plan first) |
creditsQuota / creditsRemaining | number | Credit usage tracking |
When the AI produces a workflow-updated message, AskAssistantBuild.vue calls useWorkflowUpdate().updateWorkflow() which merges incoming node changes into the canvas in-place without a full reload.
The ReviewChangesBanner.vue component shows a diff summary after an AI edit and can open AIBuilderDiffModal.vue which hosts WorkflowDiffView.vue for a side-by-side before/after comparison.
Sources: packages/frontend/editor-ui/src/features/ai/assistant/builder.store.ts128-210 packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/AskAssistantBuild.vue1-521 packages/frontend/editor-ui/src/features/ai/assistant/components/Agent/ReviewChangesBanner.vue1-20
The node creator panel (NodeCreation.vue) is lazy-loaded and controlled by nodeCreator.store. It opens from multiple triggers:
| Trigger | NodeCreatorOpenSource value |
|---|---|
| Plus endpoint button on canvas edge | "plus_endpoint" |
| Dropping a connection onto empty canvas | "node_connection_drop" |
| Keyboard shortcut (N key) | "node_shortcut" |
| Context menu "Add node" | "context_menu" |
| "Add node" button in header | "add_node_button" |
The store exposes openNodeCreatorForConnectingNode() and openNodeCreatorForTriggerNodes() as the primary entry points.
Sources: packages/frontend/editor-ui/src/features/shared/nodeCreator/nodeCreator.store.ts1-50 packages/frontend/editor-ui/src/Interface.ts675-690
Diagram: Execution Data Flow (Frontend)
Sources: packages/frontend/editor-ui/src/app/views/NodeView.vue215-216 packages/frontend/editor-ui/src/app/stores/pushConnection.store.ts
The Interface.ts file in editor-ui defines the main frontend-specific types that extend backend types with UI state:
| Type | Description |
|---|---|
INodeUi | Extends INode with position, color, notes, issues, pinData |
IWorkflowDb | Full workflow with nodes: INodeUi[], tags, sharedWithProjects, scopes, versionId |
WorkflowResource | Lightweight list-view representation (no nodes/connections) |
CanvasNodeData | Data attached to each VueFlow node; includes render type, execution status, issues, pinned data |
ModalState | Shape of entries in the ui.store modal registry |
IRunDataDisplayMode | 'table' | 'json' | 'binary' | 'schema' | 'html' | 'ai' ā NDV output display modes |
Sources: packages/frontend/editor-ui/src/Interface.ts153-163 packages/frontend/editor-ui/src/Interface.ts240-270 packages/frontend/editor-ui/src/features/workflows/canvas/canvas.types.ts102-130
NodeView.vue computes isCanvasReadOnly from several sources:
isCanvasReadOnly = isDemoRoute
|| sourceControlStore.preferences.branchReadOnly (source control locked branch)
|| collaborationStore.shouldBeReadOnly (another user is writing)
|| !(workflow update permission)
|| workflow.isArchived
|| (builderStore.streaming && !builderStore.isHelpStreaming)
When the canvas is read-only, cut/delete/paste/drag operations are silently blocked. The collaboration store tracks which browser tab holds the write lock via isCurrentTabWriter.
Sources: packages/frontend/editor-ui/src/app/views/NodeView.vue293-302
| Page | Content |
|---|---|
| Frontend Architecture and State Management | main.ts, Vue Router, Pinia stores, push connection (SSE/WS), FrontendSettings loading |
| Workflow Canvas and Node Management | NodeView, Canvas.vue, CanvasNode, useCanvasOperations, useCanvasMapping, useRunWorkflow |
| Parameter Input and Expression Editor | ParameterInput, ParameterInputFull, CodeMirror expression editor, ResourceLocator, filter/assignment editors |
| Design System and Components | @n8n/design-system components, N8nIcon registry, Lucide icons, custom SVGs |
| Internationalization System | @n8n/i18n, en.json locale structure, translation key conventions |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.