# Performance and robustness ## Data resilience: Cart and Customer management Robustness often means ensuring that data remains consistent and useful even when related resources change. Two key updates in 2025 improved how the platform handles the relationship between Customers and Carts. - Cart preservation on Customer deletion: previously, deleting a Customer record often meant losing the associated Cart data. Now, Carts are preserved when a Customer is deleted. The Cart becomes unassociated, allowing businesses to maintain accurate historical data for tax reporting, inventory management, and abandoned cart analytics without needing to keep the personal data of the deleted user. - Refined error handling for Store-specific Carts: to improve the robustness of multi-store and B2B setups, commercetools introduced better error handling for store-specific carts. If a request involves a customer who does not belong to the specific store associated with a cart, the API now provides a clear, actionable error. This prevents "silent" logic failures and makes it easier for front-end developers to guide users back to the correct store context. ## Infrastructure and Security: reliable connectivity A robust architecture requires secure and low-latency communication between commercetools and your external logic. - Google Cloud cross-cloud connectivity: API Extensions are critical to business logic. In 2025, commercetools introduced Cross-cloud connectivity for Google Cloud. This allows extensions hosted on Google Cloud to communicate with commercetools more reliably and securely, reducing the risk of timeouts and connection failures that can occur when traffic traverses the public internet. - Hardened customer account flows: we've improved how email verification and password reset tokens are managed to support more secure login flows: password reset tokens are now valid for 24 hours by default (down from 24 days), older tokens for email verification or password reset can be invalidated when a new token is created, older tokens for email verification or password reset are invalidated when a token is successfully redeemed, an error is returned when attempting to redeem an expired email verification or password reset token, and additionally, if a token's validity is 60 minutes or less, the token is now included in the Message.payload to help you build better asynchronous flows. ## Enhanced traceability: Audit Log expansion Robustness isn't just about preventing errors, it's about having the visibility to understand why they happened. In 2025, we expanded the coverage of Change Types recorded in the Audit Log, moving beyond simple "resource updated" Messages to capture specific, high-intent actions. ### What’s new in the Audit Trail? The platform now records much more specific data points when changes occur. Key highlights include: - Detailed Customer and Business Unit changes: you can now track exactly which address type was modified (billing vs. shipping) and compare the "before and after" values when sensitive fields like email addresses or Customer Group assignments are updated. - Security-centric logging: critical security events, such as password changes (`SetPasswordChange`) and changes to address Custom Fields, are now explicitly logged. This allows security teams to pinpoint exactly when a credential or sensitive attribute was modified. - Inventory and pricing governance: for businesses managing high-scale catalogs, the Audit Log now tracks changes to inventory keys, cart quantity limits, and Standalone Prices. This ensures that any change affecting a product's "orderability" or cost is fully traceable to a specific user or API client. - Resource relationship tracking: new `SetReferencesChange` logs for Cart Discounts and Discount Codes allow you to see exactly how promotional rules are being linked or unlinked from other platform resources, providing clarity on complex marketing logic. These granular audit enhancements transform logging from a passive record into a strategic tool for both technical and legal teams. By linking specific configuration changes directly to business outcomes, developers can perform rapid root-cause analysis on performance shifts, while security teams gain the verifiable "paper trail" required for SOC2 and GDPR compliance. Ultimately, this transparency removes "black box" uncertainty from the order lifecycle, ensuring every change—from pricing logic to shipping methods—is fully traceable and governed. ## Query performance: GraphQL optimization Performance in a headless environment is often measured by "chattiness"—how many API calls are required to render a page. One of the most significant performance boosts for developers is the addition of Reference Expansion for Custom Objects in GraphQL. Custom Objects are often used to store complex data (like warranty info or extra metadata) that references other resources (like Products or Categories). Previously, you would fetch a Custom Object, and if that Custom Object had any references to other resources, you had to make a second API call to get the details of those resources. Now, you can expand those references in a single GraphQL query. This reduces the number of network requests and significantly speeds up page load times for data-heavy components. **Example:** Let’s create a simple Custom Object containing a list of references to our favorite customers (feel free to use IDs of any customers in your project). To speed things up, we can do it directly using the HTTP API Playground in the Merchant Center. Navigate to **Settings ➜ Developer Settings ➜ HTTP API Playground** and select: - **Request method**: POST - **Endpoint**: Custom-objects - **Command**: Create or update CustomObject - **Body**: ```json title="Create a Custom Object that contains a list of references to favorite customers" { "container": "demo-data", "key": "favorite-customers", "value": { "customers": [ { "typeId": "customer", "id": "46fbc1a6-fd3c-424c-bbf5-096ab5da0f21" }, { "typeId": "customer", "id": "abcd0a05-e532-4673-9bd9-dd8e9545c24a" }, { "typeId": "customer", "id": "0644172f-72ec-47f0-9784-23617f3f4a80" } ] } } ``` Then, click **Send**. Once we have our Custom Object created, let’s use the GraphQL API to see if we can expand the references within it: ```ts // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example. /** * GraphQL query to fetch favorite customers from a Custom Object * * This query: * - Retrieves a Custom Object from the "demo-data" container with key "favorite-customers" * - Expands the customer references to get full customer details * - Returns customer id, email, first name, and last name for each favorite customer */ const query = ` query fetchFavoriteCustomers { customObject(container: "demo-data", key: "favorite-customers") { referencedResources(expand: "customers[*]") { path objs { ... on Customer { id email firstName lastName } } } } } `; /** * Fetches and displays favorite customers from Composable Commerce * * This function executes a GraphQL query to retrieve customer information * stored in a Custom Object and logs the results to the console. * * @returns Promise - Resolves when the query completes * @throws Logs error to console if the GraphQL query fails */ async function getFavoriteCustomers(): Promise { try { // Execute the GraphQL query via the Composable Commerce API const result = await apiRoot.graphql().post({ body: { query } }).execute(); // Log the favorite customers data in formatted JSON console.log("Favorite customers:"); console.log(JSON.stringify(result.body.data, null, 2)); } catch (error) { console.error("Error executing GraphQL query:", error); } } // Execute the function to fetch and display favorite customers await getFavoriteCustomers(); ``` ```java // Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example. /** * GraphQL query to fetch favorite customers from a Custom Object * * This query: * - Retrieves a Custom Object from the "demo-data" container with key "favorite-customers" * - Expands the customer references to get full customer details * - Returns customer id, email, first name, and last name for each favorite customer */ String query = """ query fetchFavoriteCustomers { customObject(container: "demo-data", key: "favorite-customers") { referencedResources(expand: "customers[*]") { path objs { ... on Customer { id email firstName lastName } } } } } """; try { // Build the GraphQL request object using the builder API GraphQLRequest request = GraphQLRequest.builder() .query(query) .build(); // Execute the request synchronously and get the GraphQLResponse GraphQLResponse response = apiRoot .graphql() .post(request) .executeBlocking() .getBody(); // response.getData() is an Object (POJO / Map). Convert it to JsonNode for pretty printing if (response == null || response.getData() == null) { System.out.println("Query returned no data or an empty response."); } else { ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); JsonNode dataNode = mapper.convertValue(response.getData(), JsonNode.class); String pretty = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dataNode); System.out.println("Favorite customers:\n" + JsonUtils.prettyPrint(pretty)); } } catch (Exception e) { System.err.println("Error executing GraphQL query: " + e.getMessage()); e.printStackTrace(); } } } ``` Favorite customers: ```json title="Result" { "customObject" : { "referencedResources" : [ { "path" : "customers[*]", "objs" : [ { "id" : "46fbc1a6-fd3c-424c-bbf5-096ab5da0f21", "email" : "seb@example.de", "firstName" : "Sebastian", "lastName" : "Müller" }, { "id" : "abcd0a05-e532-4673-9bd9-dd8e9545c24a", "email" : "jen@example.de", "firstName" : "Jennifer", "lastName" : "Schmidt" }, { "id" : "0644172f-72ec-47f0-9784-23617f3f4a80", "email" : "jen@example.uk", "firstName" : "Jennifer", "lastName" : "Jones" } ] } ] } } ``` There we go, thanks to this new feature, we managed to get additional information about our referenced customers and we managed to do it all using just one API request! ### Summary The 2025 updates to performance and robustness prioritize "fewer, better calls" and "safer data transitions." By optimizing GraphQL for Custom Objects, hardening infrastructure connectivity, and ensuring carts survive customer deletions, commercetools provides a more stable foundation for enterprise-grade commerce. ## Related pages - [Area overview page with navigation](/certifications.md) - [Previous page: Connect](/certifications/composable-commerce-developer-refresher-2026/connect.md) - [Next page: Other updates](/certifications/composable-commerce-developer-refresher-2026/other-updates.md) - [Search documentation and API specs](/search.md)