A Medusa.js store that works beautifully at a hundred orders a day will not automatically hold up when that number climbs to ten thousand. Performance at scale is not an afterthought you can bolt on later. It is a set of architectural decisions that need to be woven into your infrastructure from the moment you start thinking about growth.

    This guide covers the three most impactful layers of performance optimisation for Medusa.js stores: CDN configuration, Redis-based caching, and database query tuning. If you are a DevOps engineer, backend developer, or CTO evaluating how to future-proof a headless commerce build, these are the areas that will determine how well your store behaves under real traffic load.

    If you are still evaluating whether Medusa.js is the right platform for your commerce build, the Askan Technologies eCommerce development overview gives a useful starting point on how headless commerce compares to traditional coupled platforms.

    Why Performance Degrades at Scale in Medusa.js

    Medusa.js is built on Node.js and PostgreSQL with a modular architecture that gives you a great deal of flexibility. That flexibility is also where performance risks live. As store complexity grows, so does the number of database calls per request, the volume of assets served, and the strain on application servers handling concurrent sessions.

    The three most common performance bottlenecks in a scaled Medusa.js deployment are:

    • Static and semi-static assets being served directly from the application server rather than a CDN edge network

    • Repeated expensive computations and database reads that could be served from a fast cache layer

    • Unoptimised SQL queries generating excessive database load, especially on catalogue and order lookup endpoints

    Each of these has a well-defined fix. The challenge is understanding which layer is causing the most friction for your specific traffic patterns and addressing them in the right order.

    Layer 1: CDN Configuration for a Medusa.js Store

    What to Put Behind a CDN

    A Content Delivery Network serves assets from edge nodes geographically close to your users, dramatically reducing latency for repeat requests. For a Medusa.js headless storefront, CDN caching is most valuable for:

    • Product images and media files uploaded through Medusa's file service

    • JavaScript and CSS bundles from your Next.js or Remix storefront build

    • Static HTML pages generated at build time via SSG

    • API responses that return stable, infrequently changing data such as category listings and featured product collections

    Recommended CDN Setup

    Cloudflare is the most widely used CDN for Medusa.js deployments because of its generous free tier, global edge network, and straightforward cache rule configuration. For production stores with significant traffic, AWS CloudFront paired with S3 for media storage gives you tighter control over cache invalidation and origin configurations.

    A basic Cloudflare cache rule for your storefront might look like this:

    javascript
    Cache Rule: /products/* and /collections/*
    Cache Level: Cache Everything
    Edge Cache TTL: 4 hours
    Browser Cache TTL: 30 minutes
    Bypass Cache on Cookie: medusa_session (for logged-in users)

    The session cookie bypass is important. You do not want logged-in users with active carts seeing cached responses that do not reflect their session state.

    File Storage Integration

    By default, Medusa stores uploaded files locally. For any production deployment, you should replace this with an S3-compatible object storage service so your media files are served through a CDN rather than your application server. Medusa provides a first-party S3 plugin for this purpose.

    javascript
    npm install @medusajs/file-s3

    Configure the plugin in your medusa-config.js with your S3 bucket details and set your CDN URL as the base URL for media access. This alone can remove a significant proportion of load from your Medusa backend.

    Scale your Medusa.js store with us

    Let's Talk

    Layer 2: Redis Caching in Medusa.js

    Where Redis Fits in the Architecture

    Redis serves two primary roles in a Medusa.js deployment: session storage and application-level caching. Medusa uses Redis for its event bus and workflow engine by default in production, but you can extend Redis caching much further to reduce database round trips on frequently accessed data.

    Caching Product and Category Data

    Product listings, category trees, and collection data are read far more often than they are written. These are prime candidates for Redis caching with a TTL that aligns with how frequently your catalogue changes.

    A practical implementation pattern in a Medusa workflow or custom route:

    javascript
    const cacheKey = `products:category:${categoryId}`
    const cached = await redis.get(cacheKey)
    if (cached) return JSON.parse(cached)
    
    const products = await productService.list({ category_id: categoryId })
    await redis.setex(cacheKey, 3600, JSON.stringify(products))
    return products

    This pattern returns cached results instantly for the majority of requests and only hits the database when the cache expires or is explicitly invalidated after a product update.

    Cache Invalidation Strategy

    Cache invalidation is where most teams make mistakes. A simple and reliable approach for Medusa.js is to hook into Medusa's event system to invalidate relevant cache keys whenever a product or category is updated.

    javascript
    this.eventBusService_.subscribe('product.updated', async ({ id }) => {
      const keys = await redis.keys(`products:*${id}*`)
      if (keys.length) await redis.del(...keys)
    })

    This ensures your cache never serves stale data after a merchant updates their catalogue, without requiring you to use excessively short TTLs that negate the caching benefit.

    Layer 3: Database Query Optimisation

    Understanding the Most Expensive Queries

    PostgreSQL is a capable database, but unoptimised queries become a serious bottleneck at scale. The first step is visibility: enable query logging in your PostgreSQL configuration to identify slow queries in production.

    javascript
    log_min_duration_statement = 200   # Log queries slower than 200ms
    log_statement = 'none'
    

    Once you can see which queries are slow, the fixes usually fall into one of three categories: missing indexes, unnecessary joins pulling in unused columns, and N+1 query patterns.

    Adding Indexes for Commerce Queries

    Medusa's core tables are well-indexed out of the box, but custom modules and extensions you add may not be. Common index candidates for commerce workloads:

    • product_variant.product_id for fast variant lookups by parent product

    • line_item.cart_id and line_item.order_id for cart and order retrieval

    • customer.email for login and account lookup

    • order.created_at for date-range reporting queries

    Add a partial index on order status if you frequently query open or pending orders separately from completed ones:

    javascript
    CREATE INDEX idx_order_status_pending
    ON order (status) WHERE status IN ('pending', 'requires_action');
    

    Avoiding N+1 Queries in Custom Modules

    The N+1 problem is particularly common when developers build custom Medusa modules that retrieve a list of records and then loop through them to fetch related data individually. Always use eager loading via TypeORM relations when you know you need associated data.

    javascript
    // Instead of looping and fetching variants one by one:
    const products = await productRepo.find({
      relations: ['variants', 'variants.prices', 'images'],
      where: { collection_id: collectionId }
    })
    

    Monitoring and Observability

    Optimising without measurement is guesswork. Before and after each change, instrument your Medusa.js application with an observability tool so you can confirm improvements are real and catch regressions early.

    For most teams, a combination of these tools works well:

    • Datadog or New Relic for APM traces on API endpoints, showing response time breakdowns by layer

    • pganalyze or pgBadger for PostgreSQL query analysis and slow query visualisation

    • Redis Insights for cache hit rate monitoring and memory usage tracking

    • Cloudflare Analytics or AWS CloudFront metrics for CDN cache hit ratios and origin request volume

    A healthy production Medusa.js store should be targeting cache hit rates above 80% on CDN for static and semi-static content, Redis cache hit rates above 70% for product data, and P95 API response times under 300ms on core product and cart endpoints.

    The official Medusa.js documentation at docs.medusajs.com covers the infrastructure and plugin configuration options referenced in this guide and is the most reliable reference for version-specific implementation details.

    Putting the Layers Together

    CDN, Redis, and database optimisation are not independent switches you flip one at a time. They work as a layered system where each layer handles a different class of request.

    A well-optimised Medusa.js store at scale routes requests something like this: the CDN handles the first layer, serving static assets and cached API responses without touching the application at all. Requests that pass through the CDN check Redis next, where frequently accessed dynamic data is returned in sub-millisecond time. Only requests that genuinely require fresh data from the database reach PostgreSQL, and those queries are fast because they are well-indexed and use efficient query patterns.

    Getting this architecture right from the start prevents the painful and expensive re-platforming work that growing stores often face when performance problems hit them in production under real traffic.

    If you are planning a Medusa.js build or want expert help scaling an existing headless commerce deployment, Askan Technologies works with teams across the stack on Medusa.js architecture, performance, and deployment. You can also explore our DevOps and Cloud services for infrastructure support tailored to headless commerce workloads.

    Optimise your headless store performance

    Lets Talk
    K

    Written by

    Kannan Rajendiran

    CEO

    Ready to Transform
    Your Business?

    Build your next landing page fast & easy

    Available now

    Free consultation included. We'll review your requirements and provide a detailed proposal.