Netlify Blobs is a solid key-value store for unstructured data in serverless setups. The problem? Fetching those blobs from Edge Functions adds a network hop — 50–200ms every single time. Do that on every request and you’ve just killed the whole point of running on the edge.
This guide shows you how to drop a lightweight in-memory cache into your edge function and use HTTP conditional headers so your execution time drops by 80% or more.
- The Problem: Querying Netlify Blobs from edge execution environments introduces a network hop, adding 50–200ms of database latency per API request.
- The Solution: Set up a local in-memory variable cache to store blobs during the edge container’s active lifecycle, and use conditional HTTP headers.
- Immediate Gain: Sub-millisecond response times for subsequent API requests, minimal data transfer costs, and faster edge cold starts.
Why the Latency?
Netlify Edge Functions run on Deno’s V8 isolate network — code executes on servers closest to your visitors. Fast. But Netlify Blobs live in centralized storage buckets:
Edge Function Latency Loop:
[Visitor Web Request] --> [Edge Function (Tokyo)] -->|Network Hop (50-200ms)|--> [Netlify Blobs Store (Central)]
|
Returns Blob Data Payload Every await blobs.get('my-key') triggers a network hop. That’s 50–200ms of extra latency, which basically cancels out the speed you get from edge computing. The fix: cache inside the edge container itself.
Step 1: A Lightweight In-Memory Cache
Edge containers stay alive across requests. That means a global variable can hold your cached blobs in memory.
Before (no cache):
Every request hits the blob store directly:
import { getStore } from "@netlify/blobs";
export default async (request: Request) => {
const store = getStore("my-store");
// ❌ Triggers an expensive network hop on every request
const data = await store.get("config-data", { type: "json" });
return Response.json(data);
}; After (with cache):
import { getStore } from "@netlify/blobs";
// 1. Declare a global memory cache variable
interface CacheEntry {
data: any;
expiresAt: number;
}
const memoryCache = new Map<string, CacheEntry>();
export default async (request: Request) => {
const store = getStore("my-store");
const cacheKey = "config-data";
const now = Date.now();
// 2. Check if a valid cache entry exists in memory
const cached = memoryCache.get(cacheKey);
if (cached && cached.expiresAt > now) {
// ✅ Returns data in under 1 millisecond
return Response.json(cached.data, {
headers: { "X-Cache-Status": "HIT" }
});
}
// 3. Fallback to network fetch if cache is empty or expired
const freshData = await store.get(cacheKey, { type: "json" });
// 4. Update the global cache with a 5-minute Time-to-Live (TTL)
memoryCache.set(cacheKey, {
data: freshData,
expiresAt: now + 5 * 60 * 1000 // 5 minutes in milliseconds
});
return Response.json(freshData, {
headers: { "X-Cache-Status": "MISS" }
});
}; Step 2: Conditional HTTP Headers
In-memory cache helps on the server side. HTTP conditional headers help on the client side. Combine them and you’re barely moving data.
Using ETag hashes, you can tell the edge function to return a 304 Not Modified when nothing changed — zero payload transfer:
export default async (request: Request) => {
const clientETag = request.headers.get("if-none-match");
// Retrieve the latest metadata hash of the blob
const store = getStore("my-store");
const metadata = await store.getMetadata("config-data");
const currentETag = metadata?.etag || "default-hash";
// If the client's cached ETag matches the current blob hash
if (clientETag === currentETag) {
// ✅ Return instant response with 0 byte payload transfer
return new Response(null, {
status: 304,
headers: { "ETag": currentETag }
});
}
const data = await store.get("config-data");
return new Response(data, {
headers: {
"Content-Type": "application/json",
"ETag": currentETag
}
});
}; Step 3: Benchmark It
Deploy the optimized function, open Chrome’s Network panel, and see for yourself:
- Cache MISS (first request): 80–120ms — the edge isolate connects to the blob bucket.
- Cache HIT (subsequent requests): 1–3ms — data served straight from memory.
- HTTP 304 (client-side): 0 bytes over the network. Mobile users will thank you.
If you are currently scaling your system’s front-end foundations to handle high-performance workloads, review my guide on Building a Design System: Tokens, Components & Docs to align your UI elements with modern performance standards.
Frequently Asked Questions
What happens to the in-memory cache when Deno Edge Functions cold start?
Cold start = new V8 container, fresh memory, empty cache. First request will be a MISS. After that, the cache fills and stays warm for all subsequent requests on that container.
How do I manually invalidate the in-memory cache?
You can’t easily clear memory across dozens of distributed containers. Set a conservative TTL (1–5 minutes) or append a version hash like ?v=2 to your requests.
Is Netlify Blobs secure for storing sensitive user information?
Yes — data is encrypted at rest with scoped access tokens. Just make sure your handler endpoints have proper auth checks before serving sensitive blobs.
Related Articles
Deepen your understanding with these curated continuations.
How to Prevent Image Hotlinking in 2026
Stop sites from stealing your bandwidth. Block image hotlinking with Apache, Nginx, Cloudflare, AWS, Vercel, and Netlify using these copy-paste configurations.
Core Web Vitals Explained: How to Measure and Fix Your Scores
Understand Google's Core Web Vitals and their impact on SEO. Learn what LCP, INP, and CLS measure, why scores drop, and practical ways to optimize them fast.
NPM vs PNPM vs YARN vs BUN vs DENO 2026: The Ultimate Showdown
Stop guessing. This 2026 guide compares npm, pnpm, Yarn, Bun, and Deno with cold benchmarks, strict dependency rules, and honest deployment advice.