August 2026
The changes in the August 2026 releases that ask something of your project, newest first. See the August 2026 highlights for everything else that changed. Each one names the first version of each package that has it: you need the change only when you move from below that version to it or above. Where a later change replaced part of an earlier one, the earlier one says so: do what the later one asks.
The storefront packages need Next.js 16.2.11 or later
Section titled “The storefront packages need Next.js 16.2.11 or later”In: commerce-ui 0.7.0, errors 0.3.0, feature-account 0.6.0,
feature-auth 0.5.0, feature-cart 0.8.0, feature-invoice 0.8.0,
feature-order 0.11.0, feature-organization 0.8.0, feature-quote 0.12.0,
feature-return 0.7.0, feature-shopping-list 0.7.0, layout 0.3.0, ui
0.9.0
These packages declare next as a peer dependency, >=16.2.11 <17. Install
Next.js 16.2.11 or later in your storefront.
Fastify 5.12.1 or later
Section titled “Fastify 5.12.1 or later”In: cloud-adapter-gcp 0.4.0, commercetools-adyen 0.4.0,
commercetools-buckaroo 0.4.0, commercetools-mollie 0.4.0,
commercetools-paynl 0.4.0, commercetools-stripe 0.4.0, commercetools
0.11.0, contentful 0.6.0, core 1.2.0, mcp-core 1.2.0, medusa 0.4.0,
payload 0.3.0, search 0.3.0, sfcc 0.8.0, sitemap 0.2.0, storyblok
0.5.0
The fastify peer range is >= 5.12.1 < 6.0.0, because earlier versions
have a security flaw in trustProxy. Install Fastify 5.12.1 or later.
If you pass a number to trustProxy, such as http: { trustProxy: 1 } on
createApplication, it no longer type-checks, and Fastify grants no trust at
all, so request.ip becomes the nearest proxy. Pass the proxies’ IP
addresses or CIDR ranges, or a function, instead.
Custom type keys are asked for per module
Section titled “Custom type keys are asked for per module”In: commercetools 0.11.0
Each module asks only for the custom type keys of the resources it writes fields onto, and a missing key now stops the service at startup:
| Module | Keys |
|---|---|
CartModule |
order, line-item |
MultipleCartModule |
order |
CheckoutModule |
payment (no longer needed from commercetools 0.14.0) |
PaymentModule |
payment |
CustomerModule |
customer |
business-unit is no longer part of CustomTypeKeys. Remove it from the
object you pass, but keep the custom type itself provisioned: the framework
still reads its fields. One object with every key, passed to each module,
keeps working as long as it is a variable and not an inline literal.
LoadedPackage.commands is a map of loaders
Section titled “LoadedPackage.commands is a map of loaders”In: cli 0.4.0, commercetools 0.11.0, contentful 0.6.0, storyblok
0.5.0
This affects only code that uses the CLI programmatically, not the evolve
command. Call the loader to get a command’s class:
const cls = await loaded.commands.get("eject")?.();The evolve command now finds the commands of every package in your
dependencies. Contentful and Storyblok both provide eject and tf-export, so
a project that depends on both runs those two with --package.
Buckaroo returns say what happened
Section titled “Buckaroo returns say what happened”In: commercetools-buckaroo 0.4.0
A shopper used to land on your success URL whether the payment succeeded, failed, or was cancelled. Now:
| Outcome | Lands on |
|---|---|
| Paid, for an order | successUrl?success=true&orderId=… |
| Paid, for an invoice | successUrl?success=true&invoiceId=… |
| Paid, for a cart | successUrl?success=true&targetType=cart&targetId=… |
| Cancelled, failed, or pending | failureUrl?success=false&reason=…&targetId=…&targetType=… |
Check that your return pages handle these parameters.
markInvoiceUnderway takes the payment
Section titled “markInvoiceUnderway takes the payment”In: commercetools-mollie 0.4.0, commercetools 0.11.0
Pass the settling Payment instead of its id. Code that pays through
paymentCreate is not affected.
A payment no longer confirms the order
Section titled “A payment no longer confirms the order”In: commercetools-stripe 0.4.0, commercetools 0.11.0, schemas 0.11.0
An order stays OPEN until the merchant’s own system accepts it, even after
it is paid. If your storefront reads orderStatus PROCESSING as “paid”,
read Order.paymentState instead. For local development, confirm an order
with the simulator (simulate order confirm from commercetools 0.13.0).
Customer.addresses is paged and searchable
Section titled “Customer.addresses is paged and searchable”In: commercetools 0.11.0, medusa 0.4.0, schemas 0.11.0, sfcc 0.8.0
Move your selection under items:
customer { addresses { items { id city } pagination { totalCount hasNextPage } }}A schema module that declares an AddressResult field must also compose
paginationSnippet.
updateTarget and settleTarget may return no order
Section titled “updateTarget and settleTarget may return no order”In: commercetools-adyen 0.4.0, commercetools-pay-on-account 0.4.0,
commercetools-paynl 0.4.0, commercetools-stripe 0.4.0, commercetools
0.11.0, schemas 0.11.0
paymentCreate can now pay an invoice, which settles no order, so both
functions return Order | undefined. A custom payment adapter that uses the
returned order needs a check for undefined. Add the paidByPayment field to
your payment custom type.
A role’s permissions outrank roleCapabilities
Section titled “A role’s permissions outrank roleCapabilities”In: commercetools 0.11.0
The capabilities of a business unit role now come from its commercetools
permissions first, then from your roleCapabilities override, then from the
framework defaults. There is nothing to run. After upgrading, check your logs:
an override that no longer applies is logged as a warning with the role key.
If a role shows up there, change its permissions in commercetools.
MANAGE_ORDERS and MANAGE_APPROVALS are split
Section titled “MANAGE_ORDERS and MANAGE_APPROVALS are split”In: commercetools 0.11.0, medusa 0.4.0, schemas 0.11.0
| Removed | Replaced by |
|---|---|
MANAGE_ORDERS |
MANAGE_MY_ORDERS, MANAGE_OTHERS_ORDERS |
MANAGE_APPROVALS |
DECIDE_APPROVALS, MANAGE_APPROVAL_RULES |
Replace each in your gates with the half the gate means. A gate for “may act
at all” needs both. VIEW_OTHERS_CARTS is new. Of the default roles,
supervisor is new, and admin does not hold DECIDE_APPROVALS.
Associate permissions decide who may change a cart
Section titled “Associate permissions decide who may change a cart”In: commercetools 0.11.0, schemas 0.11.0
Inside a business unit, cart writes go through the associate endpoint, so commercetools checks the associate’s role. Before you upgrade, check that your roles grant what your buyers do today:
UpdateMyCartsandDeleteMyCarts, or a buyer cannot change or delete their own cart.CreateMyOrdersFromMyCarts, or checkout fails at the last step.UpdateOthersCarts,DeleteOthersCarts, andCreateOrdersFromOthersCarts, where colleagues work on each other’s carts.
Handle the new error code CART_NOT_PERMITTED.
core, federated-token, and graphql-yoga become peer dependencies
Section titled “core, federated-token, and graphql-yoga become peer dependencies”In: cloud-adapter-aws 0.2.0, cloud-adapter-azure 0.3.0,
cloud-adapter-gcp 0.4.0, commercetools-adyen 0.4.0,
commercetools-buckaroo 0.4.0, commercetools-mollie 0.4.0,
commercetools-pay-on-account 0.4.0, commercetools-paynl 0.4.0,
commercetools-stripe 0.4.0, commercetools 0.11.0, contentful 0.6.0,
core 1.2.0, json-schema-to-zod 0.2.0, mcp-core 1.2.0, medusa 0.4.0,
payload 0.3.0, search-algolia 0.1.0, search 0.3.0, sfcc 0.8.0,
sitemap 0.2.0, storyblok 0.5.0, user-notifications 0.3.0
Add these to your own dependencies if they are not there yet, in the range
the packages ask for:
| Package | Range |
|---|---|
@evolve-framework/core |
>= 1.0.0 < 2.0.0 |
@labdigital/federated-token |
>= 3.0.0 < 4.0.0, since the same release moved to 3.0.0 |
graphql-yoga |
>= 5.21.3 < 6.0.0 |
Adapters take their engine as a peer dependency
Section titled “Adapters take their engine as a peer dependency”In: commercetools-adyen 0.4.0, commercetools-buckaroo 0.4.0,
commercetools-mollie 0.4.0, commercetools-pay-on-account 0.4.0,
commercetools-paynl 0.4.0, commercetools-stripe 0.4.0, search-algolia
0.1.0, search-meilisearch 0.2.0
Add the engine package to your own dependencies:
@evolve-framework/commercetools (>= 0.10.0 < 2.0.0) for a commercetools
payment provider, and @evolve-framework/search (>= 0.2.0 < 2.0.0) for a
search adapter.
PaymentMethod.issuers is now options
Section titled “PaymentMethod.issuers is now options”In: commercetools-adyen 0.4.0, commercetools-buckaroo 0.4.0,
commercetools-mollie 0.4.0, commercetools-pay-on-account 0.4.0,
commercetools-paynl 0.4.0, commercetools 0.11.0, schemas 0.11.0
- Rename
issuerstooptionsin your queries and in any adapter you wrote. The typePaymentMethodIssueris nowPaymentMethodOption. - Remove a bank picker for iDEAL: the shopper picks their bank on the
provider’s page. Stop sending
arguments.issuerwith a payment.
Payment state keys are fixed
Section titled “Payment state keys are fixed”In: commercetools-pay-on-account 0.4.0, commercetools 0.11.0
- Remove
initialPaymentStateKeyfromCheckoutModuleandPaymentModule.DEFAULT_INITIAL_PAYMENT_STATE_KEYis gone. - Remove
creditGrantedPaymentStateKeyfromPayOnAccountPaymentAdapter. - Provision payment states with exactly these keys:
PaymentInitial(withinitial: true),PaymentPending,PaymentSuccess,PaymentFailure,PaymentRefunded,PaymentCancelled, andPaymentCreditGranted. Payments are always created in a state now.
The keys are exported as
PAYMENT_STATES and
PAYMENT_STATE_KEYS from @evolve-framework/commercetools/payments.
Buying on account records no transaction
Section titled “Buying on account records no transaction”In: commercetools-pay-on-account 0.4.0, commercetools 0.11.0
At checkout, a payment on account moves into the credit granted state, records
no transaction, and the order settles as CreditOwed. Paying the invoice later
moves the order to Paid. This change made the adapter require
creditGrantedPaymentStateKey, but the same release removed that option
again: provision the PaymentCreditGranted state instead (see
Payment state keys are fixed).
Three custom fields move to the business unit
Section titled “Three custom fields move to the business unit”In: commercetools-pay-on-account 0.4.0, commercetools-paynl 0.4.0,
commercetools 0.11.0, schemas 0.11.0
- Pay on account is granted to a business unit, through its
canPayOnAccountBoolean. It replaces the customer’spayPerInvoicefield, and a shopper outside a business unit cannot pay on account.CT_CUSTOMER_CUSTOM_FIELD_PAY_ON_ACCOUNT,PAY_ON_ACCOUNT_ACTIVATED, andPAY_ON_ACCOUNT_ON_HOLDare replaced byCT_BUSINESS_UNIT_CUSTOM_FIELD_PAY_ON_ACCOUNT. - Pay.nl reads the VAT number from
vatNumberon the business unit, not from the order’svatId.CT_ORDER_CUSTOM_FIELD_VAT_IDis gone. Customer.registrationNumberis removed from the schema.
Add canPayOnAccount (Boolean) and vatNumber (String) to your business unit
custom type, and copy the values over from the customer and order types.
PaymentCreateResponse.redirect is now next
Section titled “PaymentCreateResponse.redirect is now next”In: commercetools 0.11.0, schemas 0.11.0
next says whether the shopper goes to the provider or the payment is done.
Replace redirect { redirectUrl } in your paymentCreate selection:
next { ... on PaymentRedirect { redirectUrl } ... on PaymentComplete { order { id } }}Payments and line items carry a custom type
Section titled “Payments and line items carry a custom type”In: commercetools 0.11.0
CustomTypeKeys gained payment and line-item, and a payment and a line
item are now created with their custom type. Code that calls the
paymentCreate helper directly passes the locale and the payment type key as
one object: paymentCreate(adapter, ctApi, args, { fallbackLocale, customTypeKey }).
Which module needs which key changed again in the same release: see
Custom type keys are asked for per module.
Order.payable is required
Section titled “Order.payable is required”In: commercetools 0.11.0, medusa 0.4.0, schemas 0.11.0, sfcc 0.8.0
This affects you only if you implement Order for an engine of your own. The
field is non-null, so resolve it, for example from your payment state.
Your project owns its custom types
Section titled “Your project owns its custom types”In: commercetools 0.11.0
CartModule, MultipleCartModule, and CustomerModule require customTypes,
with the keys of the custom types your project provisions. Hold one object and
pass it to each module. CART_CUSTOM_TYPE_KEY and
NOTIFICATION_PREFERENCES_TYPE_KEY are gone. Carts and customers are created
with their type, and a service refuses to start when a configured type does
not exist. For tests, @evolve-framework/commercetools/testing exports
provisionCustomTypes, provisionPaymentStates, and TEST_CUSTOM_TYPES. The
keys each module needs changed again in the same release: see
Custom type keys are asked for per module.
Order.shippingNotice is replaced by deliveryRemarks
Section titled “Order.shippingNotice is replaced by deliveryRemarks”In: commercetools 0.11.0, schemas 0.11.0
The old field always returned a placeholder. Select Order.deliveryRemarks.
To use the fields this release reads, add them to your custom types:
cocNumber, vatNumber, and defaultPaymentMethod on the business unit,
defaultPaymentMethod on the customer, and deliveryRemarks on the cart and
order type.
paymentCreate takes a required target
Section titled “paymentCreate takes a required target”In: commercetools 0.10.0, schemas 0.10.0
PaymentContextInput.orderId and the ORDER_ID_REQUIRED error code are gone.
Name what you pay in target:
paymentCreate( target: { id: $orderId, type: ORDER } paymentContext: { … })PaymentErrorCodeType gained TARGET_NOT_FOUND, TARGET_NOT_PAYABLE,
ORDER_AWAITING_APPROVAL, PAYMENT_IN_PROGRESS, and
TRANSACTION_START_FAILED. This release also added initialPaymentStateKey to
PaymentModule, which commercetools 0.11.0 removed again.
The secret name settings for commercetools are gone
Section titled “The secret name settings for commercetools are gone”In: commercetools 0.10.0
CTP_CREDENTIALS_SECRET_NAME and CTP_USER_CREDENTIALS_SECRET_NAME are
ignored. Remove them, and set CTP_CLIENT_ID and CTP_CLIENT_SECRET instead.
Config load() is async
Section titled “Config load() is async”In: config 0.2.0, commercetools 0.10.0, contentful 0.5.0, mcp-core
1.1.0, medusa 0.3.0, sfcc 0.7.0, storyblok 0.4.3
export const loadConfig = async (): Promise<void> => { config.load({ prefix: "PURCHASE_" }); await config.load({ prefix: "PURCHASE_" });};CommercetoolsConfig and MCPCoreConfig now extend the base class from
@evolve-framework/config. A config class that
extends either adds that package to its dependencies, and imports envfield,
EnviConfig, and BaseConfig from it instead of from @labdigital/enviconf.
Two smaller changes: a string field is no longer parsed as JSON, and an empty
value counts as set.
HealthModule takes over the health routes
Section titled “HealthModule takes over the health routes”In: core 1.1.0, commercetools 0.10.0, search 0.2.0, sitemap 0.1.0
PaymentProviderModule, SearchIndexerModule, and SitemapModule no longer
serve /healthcheck, and their name option is gone. Compose
HealthModule next to them:
new CompositeModule<CommercetoolsLoaderContext>([ new PaymentProviderModule({ adapter }), new HealthModule({ name: "commercetools-adyen", graphql: false }),]);The body of /healthcheck becomes { componentName, ok, release }. A probe
that checks only the status code is not affected.
commercetools-invoice is renamed commercetools-pay-on-account
Section titled “commercetools-invoice is renamed commercetools-pay-on-account”In: commercetools-pay-on-account 0.3.0
- Replace the dependency
@evolve-framework/commercetools-invoicewith@evolve-framework/commercetools-pay-on-account, and update the imports. - Rename
InvoicePaymentAdaptertoPayOnAccountPaymentAdapter, andInvoicePaymentAdapterOptionstoPayOnAccountPaymentAdapterOptions. - Rename the service or health check name
commercetools-invoicein your deploy config.
This release also renamed the PAY_PER_INVOICE_* constants, which
commercetools-pay-on-account 0.4.0 removed (see
Three custom fields move to the business unit).
Modules declare their data loaders
Section titled “Modules declare their data loaders”In: commercetools 0.8.0, contentful 0.4.0, core 0.7.0, sfcc 0.6.0,
storyblok 0.4.0
A service no longer builds context.loaders itself:
- Remove
loadersfrom your context factory, including any placeholder or merge of two packages’ loaders. - Name your context where you compose the modules:
new CompositeModule<ContextValue>([...]). - Make sure the context carries what the loaders read:
storeContext,clientContext, andglobalScopedClientfor commercetools, alsoclientFactoryfor SFCC, andrequestfor Contentful and Storyblok.
The commercetools and SFCC packages split RequestContextValue, what your
factory builds, from ContextValue, what resolvers read. Extend
RequestContextValue in your factory. A service can no longer compose
commercetools and SFCC together. See
Caching and performance.
Cart.id is stable, and version is its own field
Section titled “Cart.id is stable, and version is its own field”In: commercetools 0.7.0, schemas 0.7.0
Cart.id used to be "<id>:<version>". It is now the bare id, and the
version is in Cart.version. Stop splitting the id. The cart mutations take an
optional version: pass it to get CART_VERSION_CONFLICT instead of
overwriting a change made elsewhere, and treat it as an opaque string.
quoteRequestCreate takes the cart in args
Section titled “quoteRequestCreate takes the cart in args”In: commercetools 0.7.0, schemas 0.7.0
# beforequoteRequestCreate(id: $cartId, args: { comment: "…" })# afterquoteRequestCreate(args: { cartId: $cartId, comment: "…" })A cart that cannot be quoted comes back in quoteRequestErrors as a
CartNotQuotableError with its reasons, instead of as an error. Handle it in
your form.
createMcpHttpDomainService moves to /application
Section titled “createMcpHttpDomainService moves to /application”In: mcp-core 0.6.0
import { createMcpHttpDomainService } from "@evolve-framework/mcp-core";import { createMcpHttpDomainService } from "@evolve-framework/mcp-core/application";storeKey, locale, and currency on InitialSessionContext are required.
Date and time fields get their own scalars
Section titled “Date and time fields get their own scalars”In: commercetools 0.6.0, schemas 0.6.0, sfcc 0.5.0
CartLineItem.addedAt is a DateTime instead of a String, so an invalid
value is rejected. Product.deliveryTime is removed. A new Date scalar holds
calendar dates without a time.
One shape for every paginated list
Section titled “One shape for every paginated list”In: commercetools 0.6.0, schemas 0.6.0, sfcc 0.5.0
orders(page: 1, pageSize: 20) { results { orderNumber } total items { orderNumber } pagination { totalCount hasNextPage hasPreviousPage }}AddressConnection,BusinessUnitAssociateConnection, andOrderApprovalConnectionare nowAddressResult,BusinessUnitAssociateResult, andOrderApprovalResult.totalCountcan be null when an engine cannot count exactly. Page withhasNextPageandhasPreviousPage.pageSizedefaults to 20 everywhere, and at most 100 is served.productspages from 1, like every other list.orderApprovalRulesreturns anOrderApprovalRuleResult.
Quotes report their real status
Section titled “Quotes report their real status”In: commercetools 0.6.0, schemas 0.6.0
The REQUESTED placeholder is gone. QuoteRequestStatusType is SUBMITTED,
ACCEPTED, REJECTED, or CANCELLED, and QuoteStatusType is PENDING,
ACCEPTED, DECLINED, EXPIRED, or CANCELLED. Quote.validUntil is new.
Search engines are pluggable adapters
Section titled “Search engines are pluggable adapters”In: commercetools 0.6.0, search 0.0.1, search-algolia 0.0.1
CatalogModuleno longer readsconfig.searchEngine. Pass a provider:search: new DocumentSearchProvider({ adapter: new AlgoliaQueryAdapter({ … }) }). Withoutsearch, it uses commercetools’ own product search.- Renamed:
CatalogSourcetoDocumentSource,ProductSyncServicetoIndexSyncService, andSearchQueryAdapter.searchProducts()tosearch(). - A
DocumentSourcedeclares itsdocumentTypes. SearchIndexerModulerefuses to start with open operational routes. Passsecret,routes: false, orallowUnauthenticatedRoutes: true.- A failed search throws instead of returning no products. Handle the GraphQL error in your storefront.
- Declare
sourceId,categoryIds, andvariants.skuasfilterOnlyattributesForFacetingon each Algolia index. A customtoRecordmust setsourceId. - The recommended Algolia setup needs new indices and a full reindex.
See Add search.
The schema-wide consistency sweep
Section titled “The schema-wide consistency sweep”In: commercetools-adyen 0.3.0, commercetools-buckaroo 0.3.0,
commercetools-mollie 0.3.0, commercetools-invoice 0.2.0,
commercetools-paynl 0.3.0, commercetools-stripe 0.3.0, commercetools
0.5.0, contentful 0.3.0, core 0.6.0, payload 0.1.0, schemas 0.5.0,
sfcc 0.4.0, storyblok 0.3.0
Run pnpm codegen and fix every query it reports:
- Scalars validate.
Currency,DateTime,EmailAddress,CountryCode,Locale,URL, andJSONreject invalid values. - Enum type names end in
Type, such asOrderStatusType, and enum values are upper snake case, such asOPEN. - Versions are opaque strings. The
versionof quotes, quote requests, order approvals, and approval rules is a nullableStringinstead of anInt. Pass it back as you got it. - Error fields are named for their domain:
refreshTokenErrorsiscustomerErrors,applePayErrorsispaymentErrors, andsetActiveBusinessContextErrorsisbusinessUnitErrors. Every…Errorslist is null on success. - Names are renamed:
redirectURLtoredirectUrl,roleIDstoroleIds,productsBySKUtoproductsBySku,previewIDtopreviewId,createPaymenttopaymentCreate,validateApplePayPaymenttoapplePayPaymentValidate,setActiveBusinessContexttobusinessUnitSwitch,setOrderApprovalStatustoorderApprovalStatusUpdate, and on shopping listsitemstolineItemsanditemIdstolineItemIds.CartLineItemCreateInputandShoppingListLineItemCreateInputend inAddInput. - A self-hosted remote payment adapter must be deployed together with the services that call it.
cache.configure takes an options object
Section titled “cache.configure takes an options object”In: core 0.5.0, cloud-adapter-azure 0.1.0
await cache.configure({ url: process.env.REDIS_URL });The ?connector=azure URL setting is gone. For Azure Managed Redis with Entra
ID, pass credentialsProvider: createEntraIdCredentialsProvider() from
@evolve-framework/cloud-adapter-azure.
The Pub/Sub handler runs on Application
Section titled “The Pub/Sub handler runs on Application”In: cloud-adapter-gcp 0.2.0, core 0.6.0
createPubSubHandler(...).createApp() returns a Promise<Application>
instead of a Fastify instance. Use app.fastify where you need Fastify, such
as for inject in tests. @evolve-framework/core/service/http no longer
exports createFastifyServer: build services with createApplication.
Test helpers move to core/testing
Section titled “Test helpers move to core/testing”In: core 0.3.0
import { assertSingleValue } from "@evolve-framework/core/utils";import { assertSingleValue } from "@evolve-framework/core/testing";
import { createGraphQLTestInstance } from "@evolve-framework/core/service/graphql";import { createGraphQLTestInstance } from "@evolve-framework/core/testing";
