CodeVetter · Repo Unpack · Extension points
n8n-io/n8n
n8n is built around registries. Backend: @Command files under commands/, @RestController classes activated by ControllerRegistry, *.module.ts backend modules via ModuleRegistry, NodeLoader implementations fed through LoadNodesAndCredentials (package dirs, custom dirs via CUSTOM_EXTENSION_ENV, module-provided loaders), @OnPubSubEvent handlers, and ExternalHooks. Nodes/credentials plug in via the package.json 'n8n' manifest. Frontend: manifest registration functions (modals, component slots, capabilities, upgrade redirects, module routes). Node types themselves expose loadOptions/listSearch/credentialTest/webhookMethods hooks.
- New CLI commands: create a class file under packages/cli/src/commands/, decorate with @Command({name, description, flagsSchema (zod)}); CommandRegistry imports commands/<name>.js by convention and runs init/run/catch/finally.
- New REST endpoints: classes decorated @RestController('/path') with @Get/@Post/@Put/@Patch/@Delete methods are activated en masse by ControllerRegistry.activate(app); most are side-effect-imported at the top of server.ts.
- New backend module: a <name>.module.ts under packages/cli/src/modules (or packages/modules) is discovered by ModuleRegistry.loadModules; modules can register entities, node loaders, commands, pubsub handlers; membership is controlled by defaultModules + ModulesConfig enabled/disabled.
- New integration node: implement INodeType (execute or declarative requestDefaults; poll/trigger/webhook/webhookMethods for triggers) under nodes/<Service>/, add the dist path to package.json 'n8n.nodes', and credentials under credentials/ with 'n8n.credentials' entries.
- Community/custom node packages: LoadNodesAndCredentials supports DirectoryLoader, PackageDirectoryLoader, LazyPackageDirectoryLoader and CustomDirectoryLoader; CUSTOM_EXTENSION_ENV adds custom directories; module nodeLoaders are appended via moduleRegistry.nodeLoaders.
- Cross-process hooks: @OnPubSubEvent/@OnLeaderTakeover/@OnLeaderStepdown/@OnShutdown decorators register handlers that PubSubRegistry.init() wires to Redis channels — but init must be re-called after modules load (explicit rewire comments in start.ts).
- ExternalHooks.run('n8n.stop', 'frontend.settings', 'activeWorkflows.initialized', ...) lets deployments inject custom logic via EXTERNAL_HOOKS config.
- Frontend extension manifests: registerModuleRoutes(router), registerEagerModals, registerComponentSlots, registerShellCapabilities, registerUpgradeRedirectGuard in main.ts — frontend modules under packages/modules/<name>/frontend plug into the editor shell through these manifests.
- Auth is a strategy chain: AuthStrategyRegistry evaluates registered strategies in order (ApiKeyAuthStrategy first, SessionCookieAuthStrategy last); modules 'can append later during their own module initialization' (e.g. token-exchange JWT).
- Node dynamic behavior hooks: methods.loadOptions, methods.listSearch, methods.credentialTest and resourceMapping let nodes serve dynamic UI data without a dedicated endpoint; DynamicNodeParametersController exposes them over REST.
- Execution context hooks: ExecutionContextHookRegistry (init'ed at the end of Start.init) lets modules hook execution-context establishment; establishExecutionContext in core consumes them.
- System tasks: mainSystemTasks(globalConfig) returns task classes registered into SystemTaskMetadata and provisioned by SystemTaskRunner on the DurableScheduler — a registry for durable background jobs.