Migration guide
The Evolve Framework is an ongoing, backwards-compatible refactoring. Not all services have been migrated yet, and APIs may still evolve. Everything described here is functional but should be considered pre-release.
This guide walks through migrating an existing Evolve service to use the
framework packages. The examples use @evolve-framework/commercetools,
but the same steps apply to other implementation packages. You can migrate
one service at a time; unmigrated services continue to work as before.
Before you start
Make sure the vendor/packages/ directory with the three framework packages
is available in your workspace. The packages are distributed as part of the
Evolve platform and do not need to be installed from a registry.
Step 1: update dependencies
Add the framework package and remove the packages it replaces:
"dependencies": {
+ "@evolve-framework/commercetools": "workspace:*",
- "@evolve-packages/http-utils": "workspace:*",
- "@evolve-packages/secrets": "workspace:*",
- "@evolve-packages/types": "workspace:*",
- "dataloader": "...",
- "@labdigital/dataloader-cache-wrapper": "...",
- "libphonenumber-js": "...",
- "zod": "..."
}
The framework re-exports everything these packages provided. Your service
gets them transitively through @evolve-framework/commercetools.
Step 2: update workspace configuration
Add the vendor packages directory to your pnpm-workspace.yaml:
packages:
- "frontend/*"
- "packages/*"
- "vendor/packages/*" # Add this line
Step 3: simplify initialization
Replace local client factory and token manager setup with the framework's configured versions:
- import { ClientFactory } from "./commercetools.ts";
- import { TokenManager } from "./core/tokens.ts";
+ import {
+ configureClientFactory,
+ configureTokenManager,
+ } from "@evolve-framework/commercetools";
export const initEnvironment = async () => {
await loadConfig();
await cache.configure(config.REDIS_URL);
- clientFactory = new ClientFactory(config);
- tokenManager = new TokenManager(config);
+ await configureClientFactory(config);
+ await configureTokenManager(config);
};
Not every service needs configureTokenManager. Only the account service
(which handles authentication directly) requires it. Other services use
federated auth and only need configureClientFactory.
Step 4: compose modules
Replace local resolver and schema imports with framework modules. Pass module configuration where needed (see module configuration for details):
- import { resolvers } from "./resolvers/index.ts";
- import { typeDefs } from "./graphql/schema.ts";
+ import {
+ CustomerGraphQLModule,
+ GraphQLCompositeModule,
+ } from "@evolve-framework/commercetools";
+
+ const module = new GraphQLCompositeModule([
+ new CustomerGraphQLModule(),
+ ]);
export const createApp = () =>
new DomainService({
+ name: config.COMPONENT_NAME,
graphql: {
- typeDefs: typeDefs,
- resolvers: resolvers,
+ typeDefs: module.getTypedefs(),
+ resolvers: module.getResolvers(),
context: newContext,
+ plugins: [useClientContext()],
},
+ http: {
+ address: { host: config.HTTP_HOST, port: config.HTTP_PORT },
+ },
});
See the available modules table for which module to use per service.
Step 5: simplify context
Replace local dataloader and client context imports with the framework's versions. The approach depends on your service's authentication model.
Federated auth (most services): use initContextValue to let the
framework create all dataloaders:
- import { createDataLoaders } from "./dataloaders/index.ts";
- import { ClientContextLoader } from "./client-context.ts";
+ import {
+ initContextValue,
+ RemoteClientContextLoader,
+ clientFactory,
+ } from "@evolve-framework/commercetools";
+ import { readStoreContextFromRequest } from "@evolve-framework/core";
export const newContext = async ({ request }) => {
- const loader = new ClientContextLoader(config);
+ const storeContext = readStoreContextFromRequest(request);
+ const loader = new RemoteClientContextLoader(
+ config.ACCOUNT_SERVICE_ENDPOINT,
+ clientFactory,
+ );
+ const clientContext = new ClientContext(storeContext, loader);
+ const context = { storeContext, clientContext };
+ initContextValue(context);
+ return context;
};
Direct auth (account service only): create dataloaders manually:
- import { createDataLoaders } from "./dataloaders/index.ts";
- import { ClientContextLoader } from "./client-context.ts";
+ import {
+ createDataLoaders,
+ CommercetoolsClientLoader,
+ clientFactory,
+ } from "@evolve-framework/commercetools";
+ import { readStoreContextFromRequest } from "@evolve-framework/core";
export const newContext = async ({ request }) => {
+ const storeContext = readStoreContextFromRequest(request);
- const loader = new ClientContextLoader(config);
+ const loader = new CommercetoolsClientLoader(clientFactory);
+ const clientContext = new ClientContext(storeContext, loader);
+ return {
+ storeContext,
+ clientContext,
+ loaders: createDataLoaders(/* ... */),
+ };
};
See context and store context for more details on these two patterns.
Step 6: update the entry point
Replace your custom process lifecycle code with ProcessManager:
+ import { ProcessManager } from "@evolve-framework/core";
+ import { cache } from "@evolve-framework/core/cache";
+ let app: DomainService;
+
+ const pm = new ProcessManager({
+ start: async () => {
+ await initEnvironment();
+ app = createApp();
+ await app.start();
+ },
+ stop: async () => {
+ await app?.stop();
+ await cache.close();
+ },
+ });
+
+ await pm.start();
ProcessManager handles SIGTERM/SIGINT for graceful shutdown and catches
startup errors.
Step 7: remove migrated files
Delete the directories and files that the framework now provides:
src/resolvers/src/dataloaders/src/mappers/src/core/src/types.tssrc/commercetools.tssrc/testing/test-server.ts
Your service should be left with init.ts, server.ts, context.ts,
and any project-specific code (REST endpoints, event handlers, jobs).
Step 8: remove tsconfig path aliases
If your service used a #src/* path alias in tsconfig.json, remove it.
Imports now come from framework packages instead of local paths.
Build order
The framework packages must build before your service. The dependency chain is:
@evolve-framework/core
→ @evolve-framework/schemas
→ @evolve-framework/commercetools
→ your service
Your build tooling (pnpm workspaces, turborepo) handles this automatically
as long as the workspace:* dependency is declared.
GraphQL codegen
Each service keeps its own codegen.ts configuration and .graphql schema
files. The framework's types are pre-generated and included in the
@evolve-framework/commercetools package, so you do not need to run
codegen for framework types.
Your service's codegen only needs to cover project-specific schema extensions.
Environment variables
The framework does not introduce any new environment variables. Your existing configuration continues to work as-is.
Gateway
The GraphQL gateway is not yet migrated to the framework and is not affected by service-level migrations. No changes to gateway configuration are needed.