Skip to content

Federation & Multi-sources

When you need multiple data sources, use scopeId on both collections and plugins. A plugin only processes collections with matching scopeId (unless ignoreScope is enabled).

Collections

Use scopeId to route a collection to the correct backend plugin.

ts
const todoCollection = defineCollection({
  name: 'todos',
  scopeId: 'main-backend',
  // Only plugins with the scopeId 'main-backend'
  // will be able to handle this collection by default
})

WARNING

If the scope ID is not defined, the collection will be handled by all plugins.

Plugins

Apply the same scopeId on the plugin side.

ts
export default definePlugin({
  name: 'my-plugin',
  scopeId: 'main-backend',
})

In the following example, the fetchMany hook will only be called with the collections that have the main-backend scope ID:

ts
export default definePlugin({
  name: 'my-plugin',
  scopeId: 'main-backend',
  setup({ hook }) {
    hook('fetchMany', async (payload) => {
      // This will only be called for collections with the scopeId 'main-backend'
    })
  }
})

You can opt-out of the filtering with the ignoreScope option of the hooks:

ts
export default definePlugin({
  name: 'my-plugin',
  scopeId: 'main-backend',
  setup({ hook }) {
    hook('fetchMany', async (payload) => {
      // This will be called for all collections regardless of their scopeId
    }, {
      ignoreScope: true,
    })
  }
})

Typical pattern

Use separate scopes for each backend, then add one plugin per scope.

ts
// Collections
defineCollection({ name: 'users', scopeId: 'main-api' })
defineCollection({ name: 'auditLogs', scopeId: 'analytics-api' })

// Plugins
definePlugin({ name: 'main-api-plugin', scopeId: 'main-api' })
definePlugin({ name: 'analytics-plugin', scopeId: 'analytics-api' })

Released under the MIT License.

directus logodirectus logo