Why this matters
- Edge caching cuts latency and origin load for read-heavy assets.
- Cache invalidation is still one of the hard problems.
- Anycast routes users to the nearest healthy edge.
- Financial APIs and static assets need different caching strategies.
CloudFront edge delivery
Edge vs origin
A CDN (Content Delivery Network) is a geographically distributed cache that stores copies of content close to users. Instead of every receipt PDF request traveling from Singapore to Virginia, the CDN serves it from a PoP (Point of Presence) in Singapore — cutting latency from 200ms to 15ms and reducing origin load by 90%+.
ShardPay's transfer APIs (POST /v1/transfers) always hit origin — they are dynamic, consistency-sensitive, and non-cacheable. Receipt PDFs, merchant logos, and compliance documents are static or semi-static, perfect for edge caching with appropriate TTL and cache keys.
CDN concepts
- CDN PoP (Point of Presence) — edge cache node in a geographic location, typically 50–200 worldwide for major CDNs. ShardPay's CDN has 180+ PoPs; a merchant in Tokyo gets receipts from the Tokyo PoP, not US-East origin.
- Cache-Control — HTTP headers that tell the CDN how long to cache (
max-age=3600), whether to revalidate (must-revalidate), and who can cache (publicvsprivate). ShardPay setsCache-Control: public, max-age=300on receipt PDFs (5-minute TTL). - Anycast — the same IP address announced from many locations; BGP routes the user to the nearest healthy PoP. ShardPay's CDN uses anycast so
cdn.shardpay.comresolves to the closest edge without client-side geo-routing logic. - Origin shield — a mid-tier cache between edge PoPs and origin, reducing origin hits when many PoPs request the same content. ShardPay's origin shield absorbs 95% of cache-miss traffic during a popular merchant's receipt re-download spike.
What to cache and what not to cache
The rule is simple: cache immutable or eventually-consistent reads; never cache writes or strongly-consistent reads. ShardPay's caching policy:
| Content | Cacheable? | TTL | Cache key |
|---|---|---|---|
| Transfer API responses | No | — | — |
| Balance lookups | No | — | — |
| Receipt PDFs | Yes | 5 min | merchantId/transferId |
| Merchant logos | Yes | 24 hr | merchantId |
| Compliance documents | Yes | 1 hr | docId |
| API JSON schemas | Yes | 1 hr | schemaVersion |
Transfer API responses
Cacheable?NoTTL—Cache key—Balance lookups
Cacheable?NoTTL—Cache key—Receipt PDFs
Cacheable?YesTTL5 minCache keymerchantId/transferIdMerchant logos
Cacheable?YesTTL24 hrCache keymerchantIdCompliance documents
Cacheable?YesTTL1 hrCache keydocIdAPI JSON schemas
Cacheable?YesTTL1 hrCache keyschemaVersion
ShardPay CDN caching policy
Caching a balance lookup would serve stale data — a user sees $100 after transferring $50. Caching a receipt PDF is safe: the PDF content is immutable once generated.
Walkthrough: receipt download during peak
A merchant downloads 10,000 receipt PDFs for tax filing. Without CDN, 10,000 requests hit ShardPay's origin API, adding load during an already-busy period. With CDN: the first request per unique PDF fetches from origin and caches at the edge PoP. The next 9,999 requests for the same PDFs serve from cache at 15ms instead of 200ms. Origin load: ~500 unique PDFs (not 10,000).
// ShardPay receipt service — cache-friendly response headers
@GetMapping("/v1/receipts/{transferId}")
public ResponseEntity<byte[]> getReceipt(@PathVariable String transferId,
@RequestHeader("Authorization") String token) {
Receipt receipt = receiptService.generateIfAbsent(transferId); // immutable once created
return ResponseEntity.ok()
.header("Cache-Control", "public, max-age=300, stale-while-revalidate=60")
.header("ETag", receipt.etag())
.header("Vary", "Authorization") // different merchants see different receipts
.contentType(MediaType.APPLICATION_PDF)
.body(receipt.pdfBytes());
}
Cache invalidation strategies
Cache invalidation is notoriously hard. ShardPay uses three strategies depending on content type:
TTL-based expiry — simplest; let the cache expire after max-age. Works for logos and compliance docs that change rarely. A logo update takes up to 24 hours to propagate — acceptable for non-critical assets.
Active purging — call the CDN's purge API when content changes. ShardPay purges a merchant's logo cache immediately after upload, so the new logo appears within 30 seconds globally.
Versioned URLs — include a content hash or version in the URL (/logos/merchant-42/v3.png). New version = new URL = automatic cache miss. ShardPay uses versioned URLs for API JSON schemas so clients always fetch the latest contract.
Caching patterns
- Cache-aside — application checks cache first, fetches from origin on miss, writes to cache. ShardPay's receipt service lets the CDN handle this transparently via
Cache-Controlheaders. - Stale-while-revalidate — serve stale content while fetching fresh copy in background. ShardPay uses
stale-while-revalidate=60on receipts so users never wait for revalidation. - Cache key design — include all dimensions that affect the response. ShardPay's receipt cache key includes
merchantIdandtransferIdso merchants never see each other's receipts. - Negative caching — cache 404 responses briefly to protect origin from repeated lookups for non-existent resources. ShardPay caches 404s for 60 seconds on receipt endpoints.
CDN for dynamic content
Some "dynamic" content benefits from edge caching with short TTL. ShardPay's merchant dashboard status page (GET /v1/merchants/{id}/status) returns semi-static data (account verified, limits configured) that changes at most once per hour. A 60-second CDN TTL reduces origin load by 80% without meaningful staleness.
True dynamic content — transfer processing, balance queries, fraud checks — must never be CDN-cached. The cost of serving a stale balance far exceeds the latency savings. When in doubt, mark it Cache-Control: private, no-store.
Quick recall
Everything you need if you only revisit this box.
- CDN helps read-heavy, immutable content — receipts and logos, not transfers.
- Cache-Control headers drive TTL; versioned URLs avoid invalidation complexity.
- Anycast routes users to the nearest PoP; origin shield protects backend from miss storms.
Test yourself
Answer these before moving on — recall is what makes it stick.