Guides

Multi-Adapter Composition

How to compose domains from multiple commerce platforms and auto-fill gaps with fallback adapters.

CommerceJS supports composing domains from different sources — Shopify for products, a custom CRM for customers, the built-in platform engine for cart/checkout. This guide walks through three composition strategies.

Strategy 1: Single Adapter

The simplest setup — one adapter handles everything:

import { createCommerce } from '@commercejs/core'
import { SallaAdapter } from '@commercejs/adapter-salla'

const commerce = createCommerce({
  adapter: new SallaAdapter({ token: '...' }),
})

The adapter's capabilities array determines which domains are available.

Strategy 2: Composite Orchestrator

Use createCompositeOrchestrator() when different domains should come from different sources:

import { createCompositeOrchestrator } from '@commercejs/core'
import { SallaAdapter } from '@commercejs/adapter-salla'
import { PlatformAdapter } from '@commercejs/platform'

const salla = new SallaAdapter({ token: '...' })
const platform = new PlatformAdapter({ db: './store.db' })

const orchestrator = createCompositeOrchestrator({
  name: 'hybrid-store',
  providers: {
    // Products from Salla
    catalog: salla,
    store: salla,
    // Cart and checkout from built-in engine
    cart: platform,
    checkout: platform,
    orders: platform,
    customers: platform,
  },
})

const commerce = createCommerce({ adapter: orchestrator })

Each domain slot is independently assignable. The orchestrator merges capabilities from all providers.

Strategy 3: Platform Fallback

Use withPlatformFallback() when you want to automatically fill gaps in a primary adapter:

import { withPlatformFallback } from '@commercejs/core'
import { SallaAdapter } from '@commercejs/adapter-salla'
import { PlatformAdapter } from '@commercejs/platform'

const salla = new SallaAdapter({ token: '...' })
const platform = new PlatformAdapter({ db: './store.db' })

// Salla supports: catalog, store, orders, customers, reviews, brands, etc.
// Platform fills gaps: cart, checkout, wishlist, returns
const orchestrator = withPlatformFallback(salla, platform)

const commerce = createCommerce({ adapter: orchestrator })

Important rules:

  • Universal domains (catalog, store) always come from the primary adapter
  • Common and specialized domains use the primary if supported, otherwise fall back
  • Capabilities are merged from both adapters

Combining Strategies

You can nest composition strategies:

import { createCompositeOrchestrator, withPlatformFallback } from '@commercejs/core'

// Step 1: Compose primary domains from multiple sources
const composite = createCompositeOrchestrator({
  name: 'multi-source',
  providers: {
    catalog: shopifyAdapter,
    store: shopifyAdapter,
    customers: crmAdapter,
  },
})

// Step 2: Fill remaining gaps with platform engine
const orchestrator = withPlatformFallback(composite, platformAdapter)

// Result: catalog + store from Shopify, customers from CRM, everything else from Platform
const commerce = createCommerce({ adapter: orchestrator })

Adding Event-Driven Providers

Providers (notifications, analytics, tax) are configured alongside the adapter in createCommerce():

const commerce = createCommerce({
  adapter: orchestrator,
  payments: {
    tap: new TapPaymentProvider({ secretKey: '...' }),
  },
  notifications: {
    resend: resendProvider,
  },
  notificationRules: [
    {
      event: 'order.created',
      channel: 'email',
      provider: 'resend',
      template: 'order_confirmation',
    },
  ],
  analytics: [ga4Provider],
})

All providers are event-driven — they subscribe to the event bus automatically when registered.

Checking Domain Support

At runtime, check what domains are available:

// Boolean check
if (commerce.hasCapability('wishlist')) {
  const wishlist = await commerce.getWishlist()
}

// Type-safe domain access on orchestrator
if (orchestrator.supports('cart')) {
  const cartAdapter = orchestrator.domain('cart')
}

// List all capabilities
console.log(orchestrator.capabilities)
// ['catalog', 'store', 'cart', 'checkout', 'orders', 'customers']