Skip to content

How Evolve fits together

Every channel of an Evolve project talks to one GraphQL API. Behind that API run your own services, and each service is a composition of modules from the Evolve packages. The modules talk to the vendors: the commerce engine, the CMS, the payment provider, the search engine, the cloud.

flowchart TB
  subgraph channels[Channels]
    site[Storefront<br/>Next.js]
    ai[AI assistants<br/>through an MCP service]
  end
  gateway[GraphQL gateway<br/>shared Hive Router image]
  subgraph services[Your services]
    discover[discover<br/>CatalogModule, CMS module, …]
    purchase[purchase<br/>CartModule, CheckoutModule, OrderModule, …]
  end
  subgraph packages[Evolve packages]
    base[schemas · core · config]
    engine[An engine<br/>commercetools, Medusa, or SFCC]
    adapters[Adapters<br/>payment, search, CMS, cloud]
  end
  subgraph vendors[Vendors]
    vendorlist[Commerce engine · CMS · payment provider · search engine · cloud]
  end
  bus[(Message bus)]
  site --> gateway
  ai --> gateway
  gateway --> discover
  gateway --> purchase
  discover --> packages
  purchase --> packages
  packages --> vendors
  services -. events .-> bus
Layer What it is Where it lives
Channels The storefront, and AI assistants through an MCP service Your repo
GraphQL gateway Combines your services into one API A shared image; your repo keeps its config
Your services GraphQL subgraphs, each a composition of modules Your repo
Framework packages The modules and the adapters to each vendor @evolve-framework/* on npm
Storefront packages Feature logic and UI primitives for the storefront @evolve-storefront/* on npm
Vendors The commerce engine, CMS, payment provider, search engine, cloud Their own SaaS or hosting

The framework packages come in families:

  • Foundations. schemas holds the GraphQL contract every engine serves, plus the message schemas for events. core runs a service: the HTTP and GraphQL server, the module system, caching, logging, and tracing. config loads a service’s settings.
  • Commerce engines. commercetools, medusa, and sfcc. Each one serves the contract from schemas against its own engine. See Engines, capabilities, and errors.
  • Adapters. One package per vendor, so a project picks the vendors it uses:
    • payment: commercetools-adyen, commercetools-buckaroo, commercetools-mollie, commercetools-paynl, commercetools-stripe, and commercetools-pay-on-account
    • search: search-algolia and search-meilisearch, on top of the provider-neutral search
    • CMS: contentful, storyblok, and payload
    • cloud: cloud-adapter-aws, cloud-adapter-azure, and cloud-adapter-gcp, for messaging, file storage, and configuration
  • Services and tools. sitemap, user-notifications (the messages that become emails), mcp-core (an MCP server on top of your API), and cli (the evolve command).

The storefront packages are the frontend counterpart: feature-* packages such as feature-cart and feature-account, and the primitives in ui. The reference lists every package.

The storefront never calls a service directly. It sends every query to the GraphQL gateway, and the gateway splits it over the subgraphs that can answer each part. A query that asks for a cart and the products in it reaches two services, and the storefront sees one response.

The gateway is a shared Hive Router image that every project runs as is. Your project keeps only two things for it: the router config and the supergraph, the combined schema that composition builds from your subgraphs’ schemas. The gateway also carries the shopper’s session between the browser and your services. See Authentication and sessions.

Federation needs one owner per entity. In the reference sites, the discover subgraph owns Product, ProductVariant, and ProductCategory. The cart and order types in @evolve-framework/schemas refer to a variant by its key only, so a line item in the purchase subgraph carries the sku, and the gateway fetches the rest of the variant from discover.

The module is the unit you install, configure, and extend. A module is a slice of the API: its schema, its resolvers, and any HTTP routes it needs, such as a webhook. AbstractModule is the base class for one.

A service is a set of modules in a CompositeModule, run by createApplication. This is the discover service of the reference B2C site, shortened:

import { CatalogModule } from "@evolve-framework/commercetools";
import { CompositeModule, HealthModule } from "@evolve-framework/core";
import { StoryblokModule } from "@evolve-framework/storyblok";
export const createModule = () =>
new CompositeModule<ContextValue>([
new CatalogModule({ clientFactory }),
new StoryblokModule({ config: storyblokConfig /* ... */ }),
new PriceTiersModule(), // the project's own module
new HealthModule({ name: "discover" }),
]);
const app = await createApplication({
name: "discover",
module: createModule(),
graphql: { context: createContext, plugins: [/* session, rate limit */] },
http: { address: { host: config.HTTP_HOST, port: config.HTTP_PORT } },
});

How you split modules over services is your choice. The reference sites run two subgraphs, plus one service that is not a subgraph:

Service Modules Answers
discover catalog, CMS everything a shopper browses before there is a cart
purchase auth, customer, cart, checkout, order, payment, shopping list, business unit everything from the cart onward
notify none; it receives notifications from the event bus turns each notification into an email

That split is an example. A smaller project can compose every module in one subgraph, and a larger one can move a domain into its own. The gateway and the storefront see the same API either way.

Your own code sits in the same place. A field the framework does not have, or a vendor without an Evolve package, becomes a module you write and add to the list. See Add your own module.

The storefront is a Next.js app in your repo. Its features come in three layers, and each one reaches you differently:

Layer What Where How updates reach you
1. Logic Hooks, queries, and mutations for a feature @evolve-storefront/feature-* npm update
2. Primitives Buttons, inputs, dialogs @evolve-storefront/ui npm update
3. Pages The markup that puts features on a page Your repo You apply the change yourself

A feature package also ships ready-made components. You style them, rearrange their parts, or take over one part’s markup, and the logic underneath stays an npm dependency. See Customize a component and Your code and ours.

Services also tell each other things without a request: a category was created, content was changed. These are internal events, each with one schema in @evolve-framework/schemas, and each says nothing about the vendor that caused it.

A module that owns a vendor turns that vendor’s webhook or subscription into an internal event and publishes it. A module that cares about the event declares which types it handles. The cloud adapter carries the event between them, over Pub/Sub, SQS, or Service Bus. A CMS module that creates a page for each new category therefore works behind any engine that publishes the event. See React to events.

B2B is modules you compose, on the same engine and the same API. The commercetools package has these on top of the B2C set:

The reference B2B site composes all five. The reference B2C site composes BusinessUnitModule and OrderApprovalModule too, without offering company accounts: the cart and order types refer to them, and the storefront’s checkout selects the approval fields. Its storefront serves both kinds of shopper: one who belongs to a business unit sees the B2B parts, and everyone else sees the B2C ones.