Performance tips

What can you do to get the best performance out of commercetools platform?

Everyone wants to be fast, everyone is afraid of the site getting slow. Although the commercetools platform is built for maximum scalability and reliable response times, there are many things a solution implementer can do in the code to keep response times low.
The following list of performance tips is not ordered by priority since the impact highly depends on the use case.
One final word: These are optimizations. It is OK, if you can’t follow them to implement a desired user experience. In other words: Don’t bother your UX person with the tips presented here to squeeze out some bits or milliseconds unless the performance impact becomes mission-critical.

API Request Planning

Please plan your API requests according to following guidelines (ordered by importance):

  1. Avoid sequential API requests wherever you can
  2. Use Reference Expansion instead of parallel or sequential requests (nowadays, network roundtrip time is more crucial than the amount of bytes transferred)
  3. Do parallel requests. All commercetools platform SDKs support these and most good generic HTTP clients, too. You will need to plan ahead concerning by which identifiers to query, because you need them in the client request or session data to do parallel requests.
  4. Avoid Reference Expansion if you do not really need it (takes time platform-internally). So better not include “expand” Parameters in your request defaults, but add them on a case-per-case Basis.

In any case, if you have use cases where commercetools platform’s querying and reference expansion facilities force you into sequential requests, please post a suggestion on our ↗ Support Portal so that we can polish the API to avoid such cases.

Querying and Showing Data

  • For a User-Facing application, always go through the Product Projections endpoint. Use the Products endpoint only to implement administration, import/export etc. The API responses will be only half as large because the projections do only contain the current or the staged version of the data (depending on how you set the staged parameter), whereas the Products endpoint always returns the current and the staged version as full copies.
  • Use the Product Projection Search endpoint wherever you can (even for fetching single products by some ID). Internally, the Product Projection Search endpoint is based on a different technology stack that delivers faster response times due to its read-only nature.
  • When querying objects:
    • Try to set a sensible limit to the number of objects returned where you can. This depends mostly on the cost of the query and on the size of the objects retrieved. As a rule of thumb, start with a small value and increase it slowly until performance starts to drop off.
    • Deactivate the field total when you are not interested in total number of results matching the query. Refer to PagedQueryResult for more details.
  • When doing bulk downloads, we recommend using the “process” implementation of our Node.js SDK “base” service, which implements best practice defaults and patterns. Feel free to implement a similar pattern in your preferred stack.

If you offer product filtering by category to your users (not the full-text search) and result should contain products assigned to filtered category plus products assigned to its subcategories use the filter by category subtree.

Matching variants

When searching for products, the platform will by default try to find the variants within the products which are matching the search criteria. Those variants are then marked in the search response with isMatchingVariant:true.
However, as it can be expensive in terms of computation power, this feature is disabled by default for better performance.
You can enable marking the matching variants by setting the parameter markMatchingVariants=true on search requests, but please consider that it may slow down the search performance. For more information, please refer to the product search section for more information.

Modifying Data

Multiple Update Actions:
  • It is possible to add a large number of update actions into one update request as long as they change the same Object (e.g. Update Product.
  • If you want to publish the updated product right away, you can include the respective publish update action into the list of update actions. It must be the last action in the list though.

Bear in mind that all update actions in one update request are treated as one transaction. That means that the whole list of update actions will fail as soon as one update action in the list fails. Thus, please think carefully which update actions you’ll put into the list of actions and which actions you better spread across different update requests.

Caching Parts of the Model

The commercetools platform has been built for stateless frontend implementations, i.e. it’s meant to simply be passed each and every user request without caching in the frontend implementation. We recommend you to really do this until you have serious and specific performance problems. You may waste a large amount of time for debugging cache staleness and its invalidation you probably not get paid for.

Nevertheless, many UI scenarios aren’t sensibly doable without caching certain parts of the commercetools platform data. This mostly refers to “Stuff in the page header”, especially category driven menu trees and metadata like product types, channels etc.

  • Although you could query the whole category tree every time, It makes sense to cache the menu as a final menu object across users. We suggest to auto-refresh it very often to avoid inconsistencies, e.g. every five seconds or so.
  • Concerning to User and Cart data it depends on how much information is directly visible in the UIs initial state. In most cases the information can be stored in an encrypted User Cookie (or a classic stateful server side session) and the full User and/or Cart Object is pulled from the commercetools platform on demand.

A notable exception to the general recommendation to avoid caching is that in some development frameworks (esp. in the CMS space) caching is built into the basic assumptions on a low level; In these cases it’s not worth fighting against the framework’s assumptions.

Import / Export / Sync Integrations

Most real world projects have some kind of (or a lot of) backend system integrations. In addition to the general advice above, these kinds of sync jobs can be implemented more elegantly by reading out the change events from the Messages API endpoint. Instead of having to bulk download everything from the commercetools platform over and over again to push changes into another system, you can simply create a job that polls the messages, remembers the “last message ID” (e.g. in a CustomObject. This way your system integrations can provide “near-time” updates and both yours and the commercetools platform load is much lower.
To be on the safe side you can do a full sync additionally every now and then.

Whether you can also do this pattern for information that is synced into the commercetools platform depends on the capabilities of the other involved system(s). As mentioned above, our Node.js SDK provides mature helpers for bulk operations.


Fetch only the fields that you need. This will result in smaller payloads, better for the network and the serialization/deserialization process.

Avoid typed product attributes and typed custom fields that adds a performance overhead, use the raw ones instead.