n8n/packages/@n8n/backend-services
n8n-assistant[bot] 86c23326c9
🚀 Release 2.42.0 (#39826)
Co-authored-by: n8n-release-helper[bot] <265227495+n8n-release-helper[bot]@users.noreply.github.com>
2026-09-29 07:11:00 +00:00
..
src refactor(core): Move UrlService to backend services (no-changelog) (#39751) 2026-09-28 11:43:39 +00:00
test build(core): Add the @n8n/backend-services package (no-changelog) (#39034) 2026-09-18 13:30:13 +00:00
eslint.config.mjs feat(core): Seal credential type writes behind the credentials repository (no-changelog) (#39106) 2026-09-22 14:42:34 +00:00
oxlint.config.mts chore: Migrate phase-one backend packages to Oxlint (no-changelog) (#39360) 2026-09-23 10:00:59 +00:00
package.json 🚀 Release 2.42.0 (#39826) 2026-09-29 07:11:00 +00:00
README.md refactor(core): Move UrlService to backend services (no-changelog) (#39751) 2026-09-28 11:43:39 +00:00
tsconfig.build.json build(core): Add the @n8n/backend-services package (no-changelog) (#39034) 2026-09-18 13:30:13 +00:00
tsconfig.json build(core): Add the @n8n/backend-services package (no-changelog) (#39034) 2026-09-18 13:30:13 +00:00
vitest.config.ts build(core): Add the @n8n/backend-services package (no-changelog) (#39034) 2026-09-18 13:30:13 +00:00

@n8n/backend-services

Backend services and HTTP error classes that many backend modules share.

Why this package exists

Backend modules live in packages/cli/src/modules/<name> today. Most of them import a small set of services from the rest of cli. A module cannot move into its own workspace package while those imports point at @/... paths in cli.

This package is the home for that shared set. It sits above @n8n/db and below n8n (cli) in the dependency graph:

flowchart TD
  cli["n8n (cli) and backend modules"] --> bs["@n8n/backend-services"]
  bs --> db["@n8n/db"]
  bs --> bc["@n8n/backend-common"]
  db --> bc

@n8n/backend-common holds the foundation that @n8n/db also needs (logger, license state, module registry, locks). @n8n/backend-services holds business and infrastructure services that need the persistence layer or that only cli and the modules consume.

What lives here

The package contains UrlService. The next PRs move the response errors, CacheService, RedisClientService, ProtectedResourceRegistry, EventService, RoleService, the finder services and the scope checks here, one area at a time.

Compatibility with cli

The package config mirrors packages/cli, so a file moved from cli compiles, lints and tests here without edits:

Concern Setup Mirrors
TypeScript common.go + backend.go, lib es2023, strictFunctionTypes, strictPropertyInitialization and useUnknownInCatchVariables off packages/cli/tsconfig.json
Lint oxlint --type-aware. eslint.config.mjs is the policy twin that code-health reads packages/cli/oxlint.config.mts, eslint.config.mjs
Tests Vitest with the decorators config, one fork per file, the same N8N_USER_FOLDER and N8N_ENCRYPTION_KEY setup packages/cli/vitest.config.base.ts, test/setup-test-folder.ts

Two things do not carry over on purpose:

  • There is no @/ path alias. cli tests load this package from dist/ and other consumers inline it from src/. tsc does not rewrite an alias in dist/, so it resolves in neither. Use relative imports inside the package.
  • cli turns a set of rules down to warn for its whole tree. This package keeps the shared backend layer as is. Fix such findings when you move a file.

Rules for adding code

  • The code must not import from n8n (cli). If it needs a cli seam, define a narrow DI port here and bind it in cli at bootstrap.
  • At least two backend modules must use the code. A service that one module uses belongs to that module.
  • Keep the file layout of cli (errors/, services/). A move with git mv keeps the history readable.
  • Add each new export to src/index.ts. Consumers import from the package root only.
  • Keep oxlint.config.mts and eslint.config.mjs in step. A ratchet allowlist for a moved TypeORM leak goes into both.