SFCC Caching (Unified Playbook)
Caching in SFCC has multiple layers. The most common failures come from:
- •choosing the wrong cache layer
- •unsafe population patterns
- •invalidation assumptions (multi-node)
- •caching the wrong data types (heavy API objects)
Quick Checklist
text
[ ] Choose cache layer: page cache (HTML) vs custom cache (data) vs service response cache [ ] Design keys with site + locale scoping where needed [ ] Use atomic get-or-load patterns (avoid double loaders) [ ] Cache POJOs/DTOs, not dw.* API objects [ ] Treat cache values as immutable snapshots; re-put updated copies [ ] Design around TTL, not cross-node invalidation [ ] Monitor hit ratios and write failures in Business Manager
Cache Layers (Pick the Right Tool)
| Layer | What it caches | When to use |
|---|---|---|
| Page cache | Rendered responses / fragments | High-traffic pages where output can be cached |
Custom cache (CacheMgr) | Application data | Expensive computations, repeated DB lookups, third-party responses |
| Service response cache | HTTP responses inside service framework | Repeated calls to stable third-party APIs |
Scope: request vs session vs CacheMgr
- •
request.custom: per-request scratchpad - •
session.custom/session.privacy: per-user, per-session data (keep small) - •
CacheMgr: app-server local cache shared by users on the same node
Never store user-specific data in a global custom cache.
Custom Cache Mechanics (Non-Negotiable Rules)
1) Define caches in caches.json and register in cartridge package.json
- •Cache IDs must be globally unique across the cartridge path.
- •The
package.jsonthat declares"caches"must live in the cartridge root (cartridges/{{mycartridge}}/package.json), and thecaches.jsonpath is relative to that.
2) Use atomic “get-or-load”
Prefer cache.get(key, loader) (single step). Avoid:
- •
if (!cache.get(key)) cache.put(key, load())
3) Cache POJOs, not API objects
Don’t cache dw.catalog.Product, dw.order.Order, etc.
Map to a lightweight object with only the fields you need.
4) Treat cached values as immutable
Values returned by cache.get are immutable copies. Do not mutate them in-place.
If you need to update cached data, write a new object back with cache.put(key, newValue).
5) TTL over invalidation
Per-key invalidation across all nodes is unreliable.
Design for a small staleness window using expireAfterSeconds.
6) Watch size limits and monitoring
- •Large entries can fail to store without throwing exceptions.
- •Use Business Manager stats (hit ratio, write failures) to validate effectiveness.
Service Response Caching (LocalServiceRegistry)
If your third-party data is stable for short periods:
- •Enable response caching on the underlying HTTP client in the service definition
- •Ensure you understand how to clear it (BM invalidation is typically global)
Key warnings:
- •stale data risk
- •debugging surprises (you may not hit the network)
- •cached calls can still affect service stats / circuit breakers
References
- •Rhino Inquisitor: Field Guide to Custom Caches
- •Rhino Inquisitor: Third-Party API Caching in Commerce Cloud
- •SFCC Docs: Custom Caches
- •SFCC Script API:
dw.system.Cache(immutable copies + value constraints) - •SFCC Script API:
dw.system.CacheMgr(cartridgepackage.jsoncache registration)