Building a KV‑backed session store in Cloudflare Workers
Step‑by‑step guide to create a Cloudflare Worker that stores user sessions in Workers KV, with configuration, testing, and rollback instructions.
12 Jun 2026, 19:25 UTC

Desired outcome
Create a Cloudflare Worker that reads and writes user session data to a Workers KV namespace, returning JSON that represents the current session or creates a new one when none exists.
Prerequisites
- A Cloudflare account with access to Workers and KV.
- Wrangler CLI installed (version compatible with Workers API).
- Node.js ≥18 for local development.
- The ID of an existing KV namespace (or permission to create one).
Procedure
Initialize a Worker project:
# Run in your terminal wrangler init session-worker --type=javascript cd session-workerAdd the KV binding to
wrangler.toml. ReplaceYOUR_KV_IDwith the namespace ID.[[kv_namespaces]] binding = "SESSION_KV" id = "YOUR_KV_ID"Implement the fetch handler in
src/index.js(orindex.tsif using TypeScript).addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { const url = new URL(request.url); const cookieHeader = request.headers.get('Cookie') || ''; const sessionIdMatch = cookieHeader.match(/session_id=([^;]+)/); let sessionId; let sessionData = {}; if (sessionIdMatch) { sessionId = sessionIdMatch[1]; const raw = await SESSION_KV.get(sessionId, { type: 'text' }); if (raw !== null) { try { sessionData = JSON.parse(raw); } catch (_) { // corrupt data – treat as missing } } } // If no valid session, create a new one if (!sessionId) { sessionId = crypto.randomUUID(); sessionData = { createdAt: new Date().toISOString(), visits: 0 }; await SESSION_KV.put(sessionId, JSON.stringify(sessionData), { expirationTtl: 3600 }); } // Example: increment a visit counter sessionData.visits = (sessionData.visits || 0) + 1; await SESSION_KV.put(sessionId, JSON.stringify(sessionData), { expirationTtl: 3600 }); const responseBody = { sessionId, ...sessionData }; return new Response(JSON.stringify(responseBody), { headers: { 'Content-Type': 'application/json', 'Set-Cookie': `session_id=${sessionId}; Path=/; HttpOnly; SameSite=Strict` } }); }Test locally with Wrangler dev:
wrangler dev # In another terminal curl -i http://127.0.0.1:8787/Deploy to Cloudflare:
wrangler publish
Expected checks
- The first request returns JSON with a newly generated
session_idand aSet-Cookieheader. - Subsequent requests that include the cookie return the same
session_idwith updated fields (e.g., incrementedvisits). - KV namespace shows the session key with a TTL of approximately one hour (visible in the Cloudflare dashboard under Workers → KV → your namespace).
- If the KV namespace is temporarily unavailable, the worker will throw; you can catch the error and return a 503 response with a maintenance message.
Recovery options (rollback)
Because this procedure creates a Worker script and binds a KV namespace, you can roll back by:
- Deleting the Worker:
wrangler delete session-worker(or via the dashboard). - Removing the KV binding from
wrangler.tomland republishing. - Optionally deleting the KV namespace if it was created solely for this worker (
wrangler kv: namespace delete SESSION_KV).
Limitations and verification
KV offers eventual consistency; a write may not be immediately visible to subsequent reads for a few seconds. Design session logic to tolerate brief stale reads (e.g., by allowing a short grace period). The default KV namespace size limit is 1 GB; monitor usage in the dashboard and consider upgrading or sharding if you approach that limit.
To verify the TTL behavior, inspect a session key in the KV dashboard shortly after creation and note the Expiration field; it should reflect the expirationTtl value (seconds) you set.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.