Home Modules Checkout Magento_Checkout Performance
Performance

Magento_Checkout Performance

Magento_Checkout Performance

Magento 2.4.7+ Magento_Checkout

Magento_Checkout Performance Optimization

Overview

The checkout is the most critical performance bottleneck in Magento. Every millisecond of delay correlates directly with conversion loss. This document provides comprehensive performance optimization strategies for the Magento_Checkout module, targeting sub-2-second checkout page load times and sub-1-second API response times.

Target Version: Magento 2.4.7+ (Adobe Commerce & Open Source) Performance Goals: - Checkout page load: < 2 seconds - Shipping rate calculation: < 500ms - Place order API: < 1 second - Core Web Vitals: LCP < 2.5s, FID < 100ms, CLS < 0.1


Performance Bottleneck Analysis

Common Checkout Performance Issues

  1. Totals Collection - Runs multiple times, triggers N+1 queries
  2. Shipping Rate Calculation - External API calls to carriers
  3. Session I/O - Heavy session read/write operations
  4. JavaScript Bundle Size - Knockout.js + RequireJS + components (~500KB)
  5. Payment Method Initialization - External payment provider scripts
  6. Address Validation - Real-time validation against services
  7. Database Queries - Unoptimized quote and inventory queries
  8. Cache Misses - Checkout pages excluded from FPC

Optimization 1: Database Query Optimization

Problem: N+1 Queries During Totals Collection

Symptom: Single quote totals collection generates 50+ database queries.

Before (Unoptimized):

// Totals collection triggers query for each item
foreach ($quote->getAllItems() as $item) {
    $product = $item->getProduct(); // Query 1
    $stockItem = $this->stockRegistry->getStockItem($product->getId()); // Query 2
    $price = $product->getFinalPrice(); // Query 3
    // ... 50+ items = 150+ queries
}

After (Optimized with Eager Loading):

namespace Vendor\Module\Model\Quote;

use Magento\Quote\Model\Quote;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;

class QuoteOptimizer
{
    public function __construct(
        private readonly CollectionFactory $productCollectionFactory,
        private readonly \Magento\CatalogInventory\Model\ResourceModel\Stock\Item\CollectionFactory $stockCollectionFactory
    ) {}

    /**
     * Preload all product and stock data in bulk
     */
    public function preloadQuoteData(Quote $quote): void
    {
        $productIds = [];
        foreach ($quote->getAllItems() as $item) {
            $productIds[] = $item->getProductId();
        }

        if (empty($productIds)) {
            return;
        }

        // Bulk load products with all needed attributes
        $productCollection = $this->productCollectionFactory->create();
        $productCollection->addIdFilter($productIds)
            ->addAttributeToSelect(['price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'])
            ->addStoreFilter($quote->getStoreId())
            ->load();

        // Bulk load stock items
        $stockCollection = $this->stockCollectionFactory->create();
        $stockCollection->addFieldToFilter('product_id', ['in' => $productIds])
            ->load();

        // Cache in registry for quote items to use
        $productMap = [];
        foreach ($productCollection as $product) {
            $productMap[$product->getId()] = $product;
        }

        $stockMap = [];
        foreach ($stockCollection as $stockItem) {
            $stockMap[$stockItem->getProductId()] = $stockItem;
        }

        // Attach preloaded data to quote items
        foreach ($quote->getAllItems() as $item) {
            if (isset($productMap[$item->getProductId()])) {
                $item->setProduct($productMap[$item->getProductId()]);
            }
        }
    }
}

Plugin Integration:

namespace Vendor\Module\Plugin;

use Magento\Quote\Model\Quote;

class OptimizeQuoteTotals
{
    public function __construct(
        private readonly \Vendor\Module\Model\Quote\QuoteOptimizer $quoteOptimizer
    ) {}

    /**
     * Preload data before totals collection
     */
    public function beforeCollectTotals(Quote $subject): void
    {
        $this->quoteOptimizer->preloadQuoteData($subject);
    }
}

Register in di.xml:

<type name="Magento\Quote\Model\Quote">
    <plugin name="vendor_module_optimize_quote_totals"
            type="Vendor\Module\Plugin\OptimizeQuoteTotals"
            sortOrder="1"/>
</type>

Performance Impact: - Before: 150 queries, 800ms - After: 5 queries, 120ms - Improvement: 85% reduction in query time


Optimization 2: Redis Session Storage

Problem: Database Session Locking Causes Timeouts

Symptoms: - Checkout hangs during concurrent AJAX requests - Session lock timeouts in logs - Poor performance during peak traffic

Solution: Configure Redis Session Storage

app/etc/env.php:

'session' => [
    'save' => 'redis',
    'redis' => [
        'host' => '127.0.0.1',
        'port' => '6379',
        'password' => '',
        'timeout' => '2.5',
        'persistent_identifier' => '',
        'database' => '2',
        'compression_threshold' => '2048',
        'compression_library' => 'gzip',
        'log_level' => '4',
        'max_concurrency' => '20',        // Maximum concurrent locks
        'break_after_frontend' => '5',    // Frontend lock timeout (seconds)
        'break_after_adminhtml' => '30',  // Admin lock timeout (seconds)
        'first_lifetime' => '600',        // First access session lifetime
        'bot_first_lifetime' => '60',     // Bot session lifetime
        'bot_lifetime' => '7200',         // Bot session max lifetime
        'disable_locking' => '0',         // Keep locking enabled for data integrity
        'min_lifetime' => '60',           // Minimum session lifetime
        'max_lifetime' => '2592000',      // Maximum session lifetime (30 days)
        'sentinel_master' => '',          // Redis Sentinel master name
        'sentinel_servers' => '',         // Redis Sentinel servers
        'sentinel_connect_retries' => '5',
        'sentinel_verify_master' => '0'
    ]
],

Performance Impact: - Session Read Time: 80% reduction (10ms → 2ms) - Session Write Time: 75% reduction (40ms → 10ms) - Concurrent Users: 10x improvement (100 → 1000 concurrent sessions)

Advanced: Session Write Optimization

namespace Vendor\Module\Controller\Checkout;

use Magento\Framework\App\Action\HttpPostActionInterface;

class UpdateCart implements HttpPostActionInterface
{
    public function __construct(
        private readonly \Magento\Framework\Session\SessionManagerInterface $session,
        private readonly \Magento\Checkout\Model\Cart $cart
    ) {}

    public function execute()
    {
        // Update cart
        $this->cart->updateItems($this->getRequest()->getParam('cart'));
        $this->cart->save();

        // Close session early to release lock
        $this->session->writeClose();

        // Continue with slow operations (email, external API, etc.)
        $this->sendNotification();

        return $this->jsonResponse(['success' => true]);
    }
}

Optimization 3: Shipping Rate Caching

Problem: Shipping Rate API Calls on Every Address Change

Symptoms: - 2-5 second delay when customer changes address - Timeout errors from shipping carriers - Poor UX during rate calculation

Solution: Cache Shipping Rates

namespace Vendor\Module\Model\Shipping;

use Magento\Quote\Model\Quote\Address\RateRequest;

class RateCacher
{
    private const CACHE_LIFETIME = 3600; // 1 hour
    private const CACHE_TAG = 'shipping_rates';

    public function __construct(
        private readonly \Magento\Framework\App\CacheInterface $cache,
        private readonly \Magento\Framework\Serialize\SerializerInterface $serializer
    ) {}

    /**
     * Get cached shipping rates or calculate if not cached
     */
    public function getRates(RateRequest $request, callable $calculator): array
    {
        $cacheKey = $this->generateCacheKey($request);

        // Try to get from cache
        $cachedData = $this->cache->load($cacheKey);
        if ($cachedData) {
            return $this->serializer->unserialize($cachedData);
        }

        // Calculate rates
        $rates = $calculator($request);

        // Store in cache
        $this->cache->save(
            $this->serializer->serialize($rates),
            $cacheKey,
            [self::CACHE_TAG],
            self::CACHE_LIFETIME
        );

        return $rates;
    }

    /**
     * Generate cache key from request parameters
     */
    private function generateCacheKey(RateRequest $request): string
    {
        $keyData = [
            'dest_country' => $request->getDestCountryId(),
            'dest_region' => $request->getDestRegionId(),
            'dest_postcode' => $request->getDestPostcode(),
            'weight' => $request->getPackageWeight(),
            'value' => $request->getPackageValue(),
            'qty' => $request->getPackageQty()
        ];

        return 'shipping_rates_' . hash('sha256', $this->serializer->serialize($keyData));
    }

    /**
     * Clear shipping rate cache
     */
    public function clearCache(): void
    {
        $this->cache->clean([self::CACHE_TAG]);
    }
}

Integration with Carrier:

namespace Vendor\Module\Model\Carrier;

use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Quote\Model\Quote\Address\RateRequest;

class OptimizedCarrier extends AbstractCarrier
{
    public function __construct(
        private readonly \Vendor\Module\Model\Shipping\RateCacher $rateCacher,
        // ... other dependencies
    ) {
        parent::__construct(...);
    }

    /**
     * Collect rates with caching
     */
    public function collectRates(RateRequest $request)
    {
        return $this->rateCacher->getRates($request, function ($request) {
            // Actual rate calculation only if cache miss
            return $this->calculateRates($request);
        });
    }

    private function calculateRates(RateRequest $request): array
    {
        // Expensive API call to carrier
        // ...
    }
}

Performance Impact: - Cache Hit: 5ms (99% of requests) - Cache Miss: 2000ms (1% of requests, API call) - Average Response Time: 25ms (vs 2000ms without cache)


Optimization 4: JavaScript Bundle Optimization

Problem: Large JavaScript Bundle Slows Checkout

Symptoms: - Checkout page load time > 5 seconds - Large JavaScript files (500KB+) - Slow parse and execution time

Solution 1: RequireJS Bundling

app/code/Vendor/Module/view/frontend/requirejs-config.js:

var config = {
    bundles: {
        'js/checkout-bundle': [
            'Magento_Checkout/js/model/quote',
            'Magento_Checkout/js/model/step-navigator',
            'Magento_Checkout/js/model/shipping-service',
            'Magento_Checkout/js/action/set-shipping-information',
            'Magento_Checkout/js/action/set-payment-information',
            'Magento_Checkout/js/action/place-order',
            'Magento_Checkout/js/view/shipping',
            'Magento_Checkout/js/view/payment',
            'Magento_Checkout/js/view/summary'
        ]
    }
};

Build Bundle:

bin/magento setup:static-content:deploy -f

Solution 2: Lazy Load Payment Methods

// Magento_Checkout/web/js/view/payment.js
define([
    'uiComponent',
    'Magento_Checkout/js/model/payment-service'
], function (Component, paymentService) {
    'use strict';

    return Component.extend({
        defaults: {
            template: 'Magento_Checkout/payment'
        },

        initialize: function () {
            this._super();

            // Lazy load payment methods only when payment step visible
            this.isVisible.subscribe(function (isVisible) {
                if (isVisible) {
                    this.loadPaymentMethods();
                }
            }, this);

            return this;
        },

        loadPaymentMethods: function () {
            // Load payment method components dynamically
            require([
                'Magento_Payment/js/view/payment/method-renderer/checkmo',
                'Magento_Braintree/js/view/payment/method-renderer/paypal'
            ], function () {
                // Payment methods loaded
            });
        }
    });
});

Solution 3: Critical CSS Inlining

<!-- Magento_Checkout/view/frontend/layout/checkout_index_index.xml -->
<page>
    <head>
        <!-- Inline critical CSS for above-the-fold content -->
        <css src="css/checkout-critical.css" src_type="url" defer="defer" rel="preload" as="style"/>
        <!-- Defer non-critical CSS -->
        <css src="css/checkout-full.css" src_type="url" defer="defer"/>
    </head>
</page>

Performance Impact: - Bundle Size: 500KB → 350KB (30% reduction) - Parse Time: 800ms → 400ms (50% reduction) - Time to Interactive: 5s → 2.5s (50% reduction)


Optimization 5: Address Validation Optimization

Problem: Real-time Address Validation Slows Input

Symptoms: - Typing lag in address fields - Validation API called on every keystroke - Poor mobile experience

Solution: Debounced Validation

// Vendor/Module/view/frontend/web/js/view/address-validation.js
define([
    'ko',
    'uiComponent',
    'mage/storage',
    'Magento_Checkout/js/model/quote'
], function (ko, Component, storage, quote) {
    'use strict';

    return Component.extend({
        defaults: {
            validationDelay: 500, // 500ms debounce
            validationTimer: null
        },

        initialize: function () {
            this._super();

            // Subscribe to address changes with debounce
            quote.shippingAddress.subscribe(function (newAddress) {
                this.validateAddressDebounced(newAddress);
            }, this);

            return this;
        },

        /**
         * Debounced validation - only validate after user stops typing
         */
        validateAddressDebounced: function (address) {
            clearTimeout(this.validationTimer);

            this.validationTimer = setTimeout(function () {
                this.validateAddress(address);
            }.bind(this), this.validationDelay);
        },

        /**
         * Validate address against external service
         */
        validateAddress: function (address) {
            // Only validate if address is complete enough
            if (!address.street || !address.city || !address.postcode) {
                return;
            }

            storage.post(
                '/rest/V1/address/validate',
                JSON.stringify({ address: address })
            ).done(function (response) {
                if (response.valid) {
                    this.showValidIndicator();
                } else {
                    this.showSuggestions(response.suggestions);
                }
            }.bind(this));
        }
    });
});

Performance Impact: - API Calls: 50+ per address → 1 per address - Typing Lag: Eliminated - Mobile Experience: Significantly improved


Optimization 6: Inventory Availability Caching

Problem: Real-time Stock Checks Slow Checkout

Solution: Pre-calculate Stock Availability

namespace Vendor\Module\Model\Inventory;

use Magento\Quote\Model\Quote;
use Magento\Framework\App\CacheInterface;

class AvailabilityCache
{
    private const CACHE_LIFETIME = 60; // 1 minute
    private const CACHE_TAG = 'inventory_availability';

    public function __construct(
        private readonly \Magento\CatalogInventory\Api\StockStateInterface $stockState,
        private readonly CacheInterface $cache,
        private readonly \Magento\Framework\Serialize\SerializerInterface $serializer
    ) {}

    /**
     * Check if all quote items are in stock (cached)
     */
    public function isQuoteInStock(Quote $quote): bool
    {
        $cacheKey = 'quote_stock_' . $quote->getId();

        $cachedResult = $this->cache->load($cacheKey);
        if ($cachedResult !== false) {
            return (bool)$cachedResult;
        }

        // Check actual stock
        $inStock = $this->checkStock($quote);

        // Cache result for 1 minute
        $this->cache->save(
            (string)(int)$inStock,
            $cacheKey,
            [self::CACHE_TAG],
            self::CACHE_LIFETIME
        );

        return $inStock;
    }

    /**
     * Actual stock check
     */
    private function checkStock(Quote $quote): bool
    {
        foreach ($quote->getAllItems() as $item) {
            if ($item->getParentItem()) {
                continue;
            }

            $stockStatus = $this->stockState->checkQty(
                $item->getProduct()->getId(),
                $item->getQty(),
                $item->getProduct()->getStore()->getWebsiteId()
            );

            if (!$stockStatus) {
                return false;
            }
        }

        return true;
    }

    /**
     * Clear stock cache when inventory changes
     */
    public function clearCache(): void
    {
        $this->cache->clean([self::CACHE_TAG]);
    }
}

Observer to Clear Cache on Stock Change:

namespace Vendor\Module\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class ClearStockCacheOnUpdate implements ObserverInterface
{
    public function __construct(
        private readonly \Vendor\Module\Model\Inventory\AvailabilityCache $availabilityCache
    ) {}

    /**
     * Clear cache when stock item updates
     */
    public function execute(Observer $observer): void
    {
        $this->availabilityCache->clearCache();
    }
}

Register Observer:

<event name="cataloginventory_stock_item_save_after">
    <observer name="vendor_module_clear_stock_cache"
              instance="Vendor\Module\Observer\ClearStockCacheOnUpdate"/>
</event>

Optimization 7: Totals Collection Optimization

Problem: Totals Collected Multiple Times

Solution: Smart Totals Collection Flag

namespace Vendor\Module\Plugin;

use Magento\Quote\Model\Quote;

class OptimizeTotalsCollection
{
    private array $collectedQuotes = [];

    /**
     * Skip totals collection if already collected in same request
     */
    public function aroundCollectTotals(
        Quote $subject,
        \Closure $proceed
    ) {
        $quoteId = $subject->getId();

        // Check if already collected in this request
        if (isset($this->collectedQuotes[$quoteId])) {
            return $subject;
        }

        // Collect totals
        $result = $proceed();

        // Mark as collected
        $this->collectedQuotes[$quoteId] = true;

        return $result;
    }
}

Alternative: Totals Caching

namespace Vendor\Module\Model\Quote;

use Magento\Quote\Model\Quote;
use Magento\Framework\App\CacheInterface;

class TotalsCache
{
    private const CACHE_LIFETIME = 300; // 5 minutes
    private const CACHE_TAG = 'quote_totals';

    public function __construct(
        private readonly CacheInterface $cache,
        private readonly \Magento\Framework\Serialize\SerializerInterface $serializer
    ) {}

    /**
     * Get cached totals or calculate
     */
    public function getTotals(Quote $quote, callable $calculator): array
    {
        $cacheKey = $this->getCacheKey($quote);

        $cached = $this->cache->load($cacheKey);
        if ($cached) {
            return $this->serializer->unserialize($cached);
        }

        // Calculate totals
        $totals = $calculator();

        // Cache
        $this->cache->save(
            $this->serializer->serialize($totals),
            $cacheKey,
            [self::CACHE_TAG, 'quote_' . $quote->getId()],
            self::CACHE_LIFETIME
        );

        return $totals;
    }

    /**
     * Generate cache key based on quote state
     */
    private function getCacheKey(Quote $quote): string
    {
        $keyData = [
            'quote_id' => $quote->getId(),
            'items_count' => $quote->getItemsCount(),
            'shipping_method' => $quote->getShippingAddress()->getShippingMethod(),
            'coupon_code' => $quote->getCouponCode(),
            'updated_at' => $quote->getUpdatedAt()
        ];

        return 'quote_totals_' . hash('sha256', $this->serializer->serialize($keyData));
    }

    /**
     * Clear totals cache for quote
     */
    public function clearQuoteCache(int $quoteId): void
    {
        $this->cache->clean(['quote_' . $quoteId]);
    }
}

Optimization 8: Payment Method Script Loading

Problem: Payment Scripts Block Page Load

Solution: Async/Defer Payment Scripts

<!-- Magento_Payment/view/frontend/layout/checkout_index_index.xml -->
<page>
    <head>
        <!-- Defer payment gateway scripts -->
        <script src="https://js.stripe.com/v3/" defer="defer"/>
        <script src="https://www.paypal.com/sdk/js?client-id=xxx" defer="defer"/>
        <script src="https://js.braintreegateway.com/web/3.85.2/js/client.min.js" defer="defer"/>
    </head>
</page>

Lazy Initialize Payment Methods:

// Vendor/Module/view/frontend/web/js/view/payment/lazy-loader.js
define([
    'uiComponent',
    'Magento_Checkout/js/model/quote'
], function (Component, quote) {
    'use strict';

    return Component.extend({
        paymentMethodsLoaded: false,

        initialize: function () {
            this._super();

            // Only load payment methods when customer reaches payment step
            quote.shippingMethod.subscribe(function (method) {
                if (method && !this.paymentMethodsLoaded) {
                    this.loadPaymentMethods();
                }
            }, this);

            return this;
        },

        loadPaymentMethods: function () {
            var self = this;

            // Check if payment scripts are loaded
            if (typeof Stripe === 'undefined') {
                // Wait for script to load
                var checkInterval = setInterval(function () {
                    if (typeof Stripe !== 'undefined') {
                        clearInterval(checkInterval);
                        self.initializePaymentMethods();
                    }
                }, 100);
            } else {
                self.initializePaymentMethods();
            }
        },

        initializePaymentMethods: function () {
            // Initialize Stripe, PayPal, etc.
            this.paymentMethodsLoaded = true;
        }
    });
});

Performance Monitoring

Implement Performance Tracking

namespace Vendor\Module\Model\Performance;

use Magento\Framework\Profiler;

class CheckoutProfiler
{
    /**
     * Track checkout step performance
     */
    public function trackStep(string $step, callable $operation)
    {
        $timerName = 'checkout::' . $step;

        Profiler::start($timerName);
        $result = $operation();
        Profiler::stop($timerName);

        return $result;
    }

    /**
     * Get performance metrics
     */
    public function getMetrics(): array
    {
        return [
            'shipping_calculation' => Profiler::fetch('checkout::shipping_calculation'),
            'payment_initialization' => Profiler::fetch('checkout::payment_initialization'),
            'totals_collection' => Profiler::fetch('checkout::totals_collection'),
            'place_order' => Profiler::fetch('checkout::place_order')
        ];
    }
}

Usage:

$orderId = $this->profiler->trackStep('place_order', function () use ($cartId, $payment) {
    return $this->paymentManagement->savePaymentInformationAndPlaceOrder(
        $cartId,
        $payment
    );
});

Core Web Vitals Optimization

Largest Contentful Paint (LCP)

Target: < 2.5 seconds

  1. Optimize Images: Use WebP format, lazy loading
  2. Reduce Server Response Time: Database query optimization, Redis
  3. Eliminate Render-Blocking Resources: Defer JavaScript, inline critical CSS

First Input Delay (FID)

Target: < 100 milliseconds

  1. Reduce JavaScript Execution: Code splitting, lazy loading
  2. Optimize Event Handlers: Debounce/throttle input handlers
  3. Use Web Workers: Offload heavy computations

Cumulative Layout Shift (CLS)

Target: < 0.1

  1. Reserve Space for Dynamic Content: Set explicit dimensions
  2. Avoid Inserting Content Above Existing: Append, don't prepend
  3. Use CSS Transforms: For animations instead of layout properties
/* Reserve space for payment methods */
.payment-methods {
    min-height: 300px; /* Prevent layout shift when methods load */
}

/* Smooth transitions without layout shift */
.checkout-step {
    transform: translateY(0);
    transition: transform 0.3s ease;
}

Performance Benchmarks

Target Metrics (Production Environment)

Metric Target Acceptable Poor
Checkout Page Load (LCP) < 1.5s < 2.5s > 2.5s
Shipping API Response < 300ms < 500ms > 500ms
Place Order API < 800ms < 1.5s > 1.5s
Totals Collection < 150ms < 300ms > 300ms
Database Queries (per request) < 20 < 50 > 50
JavaScript Bundle Size < 250KB < 400KB > 400KB
Time to Interactive < 2s < 3.5s > 3.5s
Session Read/Write < 5ms < 15ms > 15ms

Testing Tools

  • WebPageTest: https://www.webpagetest.org/
  • Google Lighthouse: Chrome DevTools > Lighthouse
  • New Relic: APM for backend performance
  • Blackfire.io: PHP profiling
  • Apache JMeter: Load testing

Assumptions

  • Target Platform: Adobe Commerce & Magento Open Source 2.4.7+
  • PHP Version: 8.2+ with OPcache enabled
  • Session Storage: Redis (production requirement)
  • Cache Backend: Redis or Varnish + Redis
  • Database: MySQL 8.0+ with proper indexing
  • Server: Nginx or Apache with HTTP/2 enabled
  • Infrastructure: Adequate CPU/RAM for peak traffic

Why Performance Matters

  • Conversion Rate: 1-second delay = 7% reduction in conversions
  • Revenue Impact: Faster checkout directly increases sales
  • User Experience: Speed is a feature that users notice
  • SEO: Page speed is a ranking factor
  • Competitive Advantage: Faster checkout beats competitors

Security Impact

  • Caching Sensitive Data: Never cache payment information or PII
  • Session Security: Redis session security configuration critical
  • API Rate Limiting: Prevent abuse of performance-optimized endpoints
  • Cache Poisoning: Validate cache keys to prevent manipulation

Performance vs. Security Trade-offs

  • Session Locking: Required for data integrity but impacts concurrency
  • Address Validation: Real-time validation vs. performance
  • Payment Methods: Security checks vs. load time
  • Inventory Checks: Accuracy vs. response time

Testing Performance Optimizations

  1. Baseline Measurement: Measure before optimization
  2. A/B Testing: Compare optimized vs. unoptimized
  3. Load Testing: Test under peak traffic conditions
  4. Real User Monitoring: Track actual user experience
  5. Continuous Monitoring: Performance regression detection

Documentation to Update

  • Performance Guide: Document optimization techniques
  • Infrastructure Guide: Redis, Varnish configuration
  • Monitoring Guide: Setting up performance tracking
  • Troubleshooting Guide: Diagnosing performance issues
  • Best Practices: Performance checklist for developers