Skip to main content

Overview

@egose/n8n-sync syncs workflows, credentials, and optionally execution summaries between n8n instances using n8n external hooks. It builds two self-contained CommonJS hook bundles that you deploy alongside n8n and point at via EXTERNAL_HOOK_FILES.

BundleRole
dist/publisher.cjsRuns on the source instance. Lifecycle hooks POST sync events to one or more subscribers. HTTPS is required outside development/test.
dist/subscriber.cjsRuns on each target instance. Mounts an endpoint on n8n's own server and applies events via n8n's internal repositories.

How it works​

┌──────────────┐ credentials.create/update/delete ┌──────────────┐
│ source n8n │ workflow.afterCreate/afterUpdate/… │ target n8n │
│ │ ──────────────────────────────────────► │ (1..n) │
│ publisher.cjs│ POST /rest/sync/v1/events │subscriber.cjs│
│ │ HMAC-signed or bearer-token auth │ │
└──────────────┘ └──────────────┘
  • Fan-out: the publisher delivers every event to every URL in SYNC_SUBSCRIBER_URLS. Hook preparation and emission are serialized per source entity, and each target has its own serialized in-memory queue. Slow or unreachable targets do not delay other targets.
  • Fire-and-forget hooks: deliveries run in the background and failures are retried with exponential backoff (1s, 2s, 4s, capped at 10s) then logged, so a sync outage cannot break n8n operations. Publisher hooks never throw.
  • Durable event identity: every emitted event includes sourceId, eventId, and a monotonic per-entity entityRevision. Publisher counters live under SYNC_PUBLISHER_STATE_PATH; subscriber checkpoints and tombstones live under SYNC_SUBSCRIBER_STATE_PATH.
  • Idempotent subscriber: the subscriber applies events through the target instance's own TypeORM repositories, resolved from n8n's DI container inside n8n.ready.
  • Encrypted credentials only: credential data is passed through as the stored encrypted string blob. All instances must share the same N8N_ENCRYPTION_KEY so targets can decrypt secrets at runtime.

Synced entities​

By default n8n-sync keeps workflows and credentials mirrored across instances. Execution sync is opt-in because it is high-volume.

EntityWired by defaultOpt-in env
WorkflowsyesSYNC_ENTITIES (remove workflows to disable)
CredentialsyesSYNC_ENTITIES (remove credentials to disable)
Executions ★noSYNC_ENTITIES=...,executions

★ workflow.postExecute fires per execution (high volume) and the publisher handler is fire-and-forget so it never blocks n8n. Only scalar lifecycle columns are mirrored; per-step fullRunData is dropped. executions requires workflows to be enabled.

Supported runtime​

The subscriber runtime adapter is pinned and contract-tested against n8n 2.31.2. The package lazy-loads @n8n/di and @n8n/db from the official Docker image paths by default, with N8N_DI_PATH and N8N_DB_PATH overrides for custom layouts.

Where to go next​