Shopware 6.7 represents a massive leap in performance engineering. Beyond PHP 8.3 support and improved dependency injection, the release refines how data is cached across every layer of the stack. For developers and architects, mastering the caching architecture in Shopware 6.7 is no longer optional; it's essential for delivering high-performance storefronts and responsive backend experiences.

This guide breaks down the core caching mechanisms in Shopware 6.7, including HTTP cache nuances, Redis integration, and best practices for cache invalidation.

The Multi-Layer Caching Architecture

Shopware 6.7 relies on a tiered approach to keep data close to the user while maintaining consistency:

  1. Edge/HTTP Cache: Varnish or Nginx FastCGI cache serving static and semi-dynamic content.
  2. Application Cache (Redis/Symfony Cache): Session storage, state machine locks, and temporary application state.
  3. Query Cache: Database-level caching handled by the underlying RDBMS.

HTTP Cache and ESI in Shopware 6.7

Shopware 6.7 enhances the Cache-Control header generation logic to maximize hit rates while preventing data leakage. The system automatically manages public vs. private content using Symfony's HTTP cache component.

Key Improvements in 6.7

  • Granular Cache Keys: Cache keys now include more context variables (currency, language, store switcher state) out of the box, reducing the need for manual key customization in multi-store setups.
  • ESI Zones: Shopware uses Embedded Sub-Requests (ESI) for dynamic fragments like the cart summary or price lists. In 6.7, ESI handling is optimized to reduce latency and improve cache hit ratios on these fragments.
  • Customer Context Tokens: Personalized content is hashed using a unique token that expires based on the customer's login state. This ensures guest users share cached responses while logged-in users receive isolated, secure payloads.

To leverage this, ensure your Varnish or Nginx configuration respects Surrogate-Control headers for ESI zones and does not overwrite Vary headers related to cookies or tokens.

Redis: The Heart of Shopware 6.7 Runtime

Redis is no longer just a "nice-to-have" in Shopware 6.7; it is the backbone of application state.

Core Redis Use Cases

  • Session Management: Storefront and Administration sessions are persisted in Redis by default. This allows for horizontal scaling without sticky sessions.
  • State Machine Locking: Inventory updates during checkout use Redis locks to prevent overselling. The locking mechanism is atomic and race-condition-free, critical for high-concurrency sales events.
  • Cache Backend: Shopware uses Redis as the primary backend for the cache.app pool and entity tag invalidation.

Configuration in 6.7

Configuration is typically managed via environment variables. In .env, ensure your Redis connection is robust:

REDIS_HOST=redis://127.0.0.1:6379/0
SESSION_SAVE_HANDLER=redis
CACHE_STORE=redis

Shopware 6.7 supports connection pooling and serialization optimizations out of the box. You can customize serialization via config/packages/cache.yaml if you need to tune performance for specific object graphs, though the default serializer handles Shopware entities efficiently.

Code Example: Safe Cache Injection and Tagging

In Shopware 6.7, developers should use PSR-6 compliant interfaces rather than accessing internal services directly. Below is a pattern for injecting the cache and invalidating by tags, which is the recommended approach for consistency.

src/Service/ProductCacheService.php

declare(strict_types=1);

namespace App\Service;

use Psr\Cache\CacheItemPoolInterface;
use Shopware\Core\Framework\Adapter\Cache\CacheInvalidatorInterface;

final readonly class ProductCacheService
{
    public function __construct(
        private CacheItemPoolInterface $cache,
        private CacheInvalidatorInterface $invalidator,
    ) {
    }

    public function getCachedPrices(string $productId): array
    {
        $key = "product_prices_{$productId}";
        $item = $this->cache->getItem($key);

        if ($item->isHit()) {
            return $item->get();
        }

        // Fetch logic...
        $prices = $this->fetchPricesFromDatabase($productId);

        $item->set($prices);
        $item->expiresAfter(3600); // Cache for 1 hour
        
        // Tagging is crucial for invalidation!
        $item->tag(["product.{$productId}", "pricing"]);
        
        $this->cache->save($item);

        return $prices;
    }

    public function invalidateProductPrices(string $productId): void
    {
        // Invalidate specific tags instead of clearing the whole store
        $this->invalidator->invalidateTags(["product.{$productId}", "pricing"]);
    }

    private function fetchPricesFromDatabase(string $productId): array
    {
        // Database access logic...
        return [];
    }
}

Registration in services.xml

<service id="App\Service\ProductCacheService">
    <argument type="service" id="cache.app" />
    <argument type="service" id="Shopware\Core\Framework\Adapter\Cache\CacheInvalidatorInterface" />
</service>

Key Takeaways from the Code:

  • Constructor Injection: Uses PHP 8 readonly classes and typed properties, standard in SW6.7.
  • Tagging: We associate tags with cache items. When a product is updated in the admin, the system can invalidate product.{id} tags automatically via the SaveEntityEvent, keeping custom caches consistent without full flushes.
  • Expiration: Explicit TTL management prevents stale data indefinitely.

Cache Warmer and Deployment Performance

Shopware 6.7 improves the sw:cache:warmup command significantly. During deployment, Shopware pre-generates essential cache keys for navigation structures, categories, and plugin configurations.

In 6.7, the warmer runs in parallel where possible, reducing downtime. You can also implement custom warmers by implementing Shopware\Core\Framework\Adapter\Cache\CacheWarmerInterface. This allows plugins to inject their own configuration into the application cache during installation or updates.

Best Practices for Shopware 6.7

  1. Always Use Tags: Never rely on invalidateStore() in production logic. Use tags to target specific data groups.
  2. Monitor Redis Latency: Redis performance directly impacts TTFB. Monitor memory usage and evictions.
  3. Entity Definition Tags: When creating custom entities, implement getTaggableFields() or use the EntityDefinition hooks to ensure your entity triggers appropriate cache invalidations automatically.
  4. Environment Switching: Use SW_CACHE_STORE to switch backends during debugging (e.g., to array for local dev), but always enforce redis in production environments via .env.

Conclusion

Shopware 6.7 provides a robust, scalable caching infrastructure that handles complexity behind the scenes. By understanding HTTP cache headers, leveraging Redis for state management, and using tag-based invalidation in your custom code, you can build store experiences that are fast, consistent, and ready for scale. Keep an eye on the migration guides when upgrading, as some internal cache services have been deprecated in favor of PSR standards to ensure long-term maintainability.