n8n/packages/frontend/@n8n/frontend-module-sdk
n8n-release-tag-merge[bot] c09da09d38 Merge tag 'n8n@2.37.0'
2026-08-25 09:42:46 +00:00
..
src feat(editor): Route instance-ai credits push through the module SDK (no-changelog) (#34436) 2026-08-25 07:56:33 +00:00
.gitignore refactor(editor): Extract module contract and registries into @n8n/frontend-module-sdk (no-changelog) (#34080) 2026-07-14 09:20:00 +00:00
biome.jsonc refactor(editor): Extract module contract and registries into @n8n/frontend-module-sdk (no-changelog) (#34080) 2026-07-14 09:20:00 +00:00
eslint.config.mjs refactor(editor): Extract module contract and registries into @n8n/frontend-module-sdk (no-changelog) (#34080) 2026-07-14 09:20:00 +00:00
package.json 🚀 Release 2.37.0 (#36986) 2026-08-25 07:32:14 +00:00
README.md feat(editor): Route instance-ai credits push through the module SDK (no-changelog) (#34436) 2026-08-25 07:56:33 +00:00
tsconfig.json refactor(editor): Extract module contract and registries into @n8n/frontend-module-sdk (no-changelog) (#34080) 2026-07-14 09:20:00 +00:00
vite.config.ts refactor(editor): Extract module contract and registries into @n8n/frontend-module-sdk (no-changelog) (#34080) 2026-07-14 09:20:00 +00:00

@n8n/frontend-module-sdk

The frontend module contract and registries for n8n editor modules.

This package owns the FrontendModuleDescription descriptor type plus the modal and resource registries that features register against. The editor shell keeps the wiring (moduleInitializer) that drives the two-phase lifecycle; this package only defines the contract and the registry state.

It is a source-only package (no build step): consumers resolve it from src via the editor-ui Vite alias and tsconfig paths, and src/index.ts is the only public entry point.

import { modalRegistry, registerResource, type FrontendModuleDescription } from '@n8n/frontend-module-sdk';

Push handlers

A module owns a push message type when it declares it in pushHandlers. The shell dispatches these at app scope, so a handler runs in every layout. The shell skips its own built-in handler for a type a module owns.

Contract: a handler must not depend on the built-in handling of the same event. The two run on separate listeners, so their order is not defined.