This repository shows how an organization can let teams own separate EventCatalogs while publishing one organization-wide catalog.
This guide covers the new built-in, lockfile-based Federation commands. It does not use the older @eventcatalog/generator-federation copy generator.
Federation combines independently owned catalogs without moving their source documentation into one repository.
- A team catalog owns and versions its domains, systems, services, messages, schemas, and other documentation.
- A federating catalog selects the team catalogs that belong in its view.
- EventCatalog resolves relationships between those catalogs and builds one connected catalog.
- A lockfile pins every source to a commit, so local and CI builds use the same documentation.
flowchart LR
subgraph Teams[Team-owned repositories]
PAY[Payments catalog]
ORD[Orders catalog]
FUL[Fulfillment catalog]
end
PAY -->|index and content| FED[Organization catalog]
ORD -->|index and content| FED
FUL -->|index and content| FED
FED --> LOCK[eventcatalog.lock]
FED --> SITE[One connected documentation site]
The organization catalog is a composition point, not the owner of every document. Teams still review and change their documentation through their normal repositories.
Federation runs three stages before dev, build, or generate:
- Index — describe each catalog's resources, relationships, files, and content hashes.
- Resolve — join the indexes into one graph and resolve references across catalog boundaries.
- Hydrate — fetch the pinned files and write them to the generated
federated/directory.
flowchart LR
A[Team catalogs] --> B[Build or fetch indexes]
B --> C[Resolve one graph]
C --> D{Ownership conflicts?}
D -->|Yes| E[Stop the build]
D -->|No| F[Hydrate pinned content]
F --> G[Build the catalog]
If a source repository contains catalog.index.json, EventCatalog uses it. Otherwise, EventCatalog checks out the source and creates the index itself.
Each directory is a standalone EventCatalog project.
| Directory | Owner | Scope |
|---|---|---|
customer-identity |
Customer Identity Team | Profiles, authentication, sessions, and addresses |
catalog |
Product Catalog Team | Products, categories, and search indexing |
pricing-and-promotions |
Pricing & Promotions Team | Prices, promotions, and coupons |
cart-and-checkout |
Checkout Experience Team | Carts, checkout orchestration, and tax |
orders |
Order Management Team | Orders, order history, and lifecycle |
payments |
Payments Platform Team | Payments, refunds, fraud, and providers |
fulfillment |
Fulfillment Operations Team | Inventory, warehouses, shipping, and carriers |
platform |
Developer Platform Team | Runtime, CI/CD, observability, and developer tooling |
central-catalog |
Reviews & Trust Team | The federated view and organization-owned reviews documentation |
Every resource, team, and user in this example has one owning catalog. The central catalog owns only the Reviews domain and its Reviews & Trust team; the other domains stay in their team catalogs and appear in the organization view through Federation.
Each team needs a valid EventCatalog in a GitHub repository. The catalog can be at the repository root or in a subdirectory.
Before adding sources, agree on these rules:
- Every resource ID has one owning catalog across the organization.
- All versions of a resource stay with the same owning catalog.
- Shared users and teams are defined once, not copied into every catalog.
- Consumers reference another team's resource by ID; they do not create a second MDX definition for it.
- When migrating from the copy generator, remove copied resources and dependency placeholders that repeat an owner's ID.
These rules matter because Federation rejects duplicate IDs and type collisions instead of choosing a winner.
Use an EventCatalog release that provides the built-in commands:
npx eventcatalog federation --helpFederation is an EventCatalog Enterprise feature. Make the Scale license key available to local commands and CI:
export EVENTCATALOG_SCALE_LICENSE_KEY=your-license-keyKeep generated files out of Git by adding these entries to the federating catalog's .gitignore:
federated/
.eventcatalog-cache/Commit eventcatalog.lock; do not ignore it.
Run commands from the federating catalog:
cd central-catalog
npx eventcatalog federation add github:acme/payments-catalogIf the catalog is inside the source repository, pass its path:
npx eventcatalog federation add github:acme/payments --path catalogThis repository demonstrates the monorepo pattern. Multiple catalogs use the same GitHub repository, so each source also needs a unique ID:
npx eventcatalog federation add github:acme/federation-organization-example \
--path payments \
--id acme/payments
npx eventcatalog federation add github:acme/federation-organization-example \
--path orders \
--id acme/ordersRepeat the command for each team catalog. federation add:
- checks the new source against sources already added;
- reports duplicate ownership and unresolved references;
- adds the source to
eventcatalog.config.js; and - pins the source commit and index digest in
eventcatalog.lock.
Use --dry-run to check a source without changing either file:
npx eventcatalog federation add github:acme/payments --path catalog --dry-runThe generated configuration has this shape:
export default {
// The rest of the catalog configuration
federation: {
sources: [
{
id: 'acme/payments',
source: 'github:acme/payments',
path: 'catalog',
mode: 'hydrate',
},
],
},
};The built-in GitHub source currently uses the github:owner/repository locator. The machine running Federation must be able to fetch the repository and its raw files.
npx eventcatalog federation status
npm run devstatus shows the pinned commit, mode, age, resource count, conflicts, and references that are not yet federated.
dev, build, and generate automatically prepare the federated content from eventcatalog.lock. Do not edit anything under federated/; it is replaced on the next run.
A consumer references the ID owned by another team. For example, the Fulfillment catalog can receive an event owned by Payments:
---
id: fulfillment-service
name: Fulfillment Service
version: 1.0.0
receives:
- id: payment-captured
version: 1.0.0
---Only Payments defines the payment-captured event. Fulfillment does not copy the event or create a placeholder resource. The reference can remain external while working on the team catalog; it resolves when both sources are present in the federating catalog.
Version behavior is predictable:
- no version or
latestselects the highest available version; - an exact version selects that version; and
- a semantic version range selects the highest matching version.
A reference to a missing ID is reported but does not block adding the source. Duplicate ownership, conflicting resource types, and pointer type mismatches do block the federated build.
| Mode | Behavior | Use it when |
|---|---|---|
hydrate |
Fetches the remote documentation, schemas, specifications, sidecars, and assets into federated/ |
Users need the remote resource pages in this catalog. This is the default. |
reference |
Keeps the source in the resolved graph but does not write its remote files | The graph relationship is needed but the remote documentation should not be materialized. |
Set the mode when adding or updating a source:
npx eventcatalog federation add github:acme/payments --path catalog --mode referenceEach team keeps its catalog with its code and the organization catalog federates those repositories. This gives teams independent review and release cycles and is the clearest default for most organizations.
Keep documentation beside a service or product using a folder such as catalog/, then add it with --path catalog. This avoids creating a documentation-only repository.
Use a different --path and --id for every catalog. This repository uses that layout. A source ID must be stable because it is recorded in the lockfile and federation graph.
Let teams own implementation-level resources. Keep only organization-wide material in the central catalog, such as cross-domain flows, architecture decisions, shared taxonomy, and global teams or users.
The same team catalog can be a source for more than one federating catalog. For example, an organization can publish a company view and smaller business-unit views without copying the team documentation.
- IDs are organization-wide identifiers, not repository-local identifiers.
- One source owns an ID and all of its versions.
- Local content in the federating catalog must not reuse an ID owned by a source.
- Cross-catalog relationships use pointers such as
sends,receives,services,domains,flows, and flow steps. - Assets under
public/andcomponents/should use distinct paths. Different files at the same shared path produce a collision warning. - Adding a source with an ownership conflict writes nothing. Fix the ownership boundary, then add it again.
Federated builds do not silently move to the latest source commit. To update a source, rerun its federation add command:
npx eventcatalog federation add github:acme/payments --path catalogReview and commit the resulting eventcatalog.config.js and eventcatalog.lock changes. CI then installs the central catalog and builds it with the Scale license key:
npm ci
npm run buildThis produces a repeatable release: the config says which catalogs participate, and the lockfile says exactly which version of each catalog was used.
| Message or symptom | What to do |
|---|---|
eventcatalog.lock is missing |
Run eventcatalog federation add for the configured sources and commit the lockfile. |
Source ... is not in the lockfile |
Add that source again so its config and lock entry agree. |
| Ownership conflict | Remove the copied or placeholder resource from the non-owning catalog, or assign a different globally unique ID. |
| Reference is not yet federated | Add the owning catalog, or correct the referenced ID or version. |
| Federated content looks stale | Rerun federation add for the source to pin its new commit, then rebuild. |
| Federation cannot fetch content | Check the github: locator, --path, repository access, and source commit. |
Each team catalog can still run on its own:
cd cart-and-checkout
npm run devBuild an individual catalog with:
cd payments
npm run build