Using a Key-Value Store with Next.js App Router
A complete guide to integrating a remote key-value store with Next.js 15 App Router. Server actions, caching, and persistence explained.
The Next.js App Router (introduced in version 13/14) completely changed how we build React applications. We moved from useEffect data fetching to Server Components and Server Actions.
This shift makes a remote Key-Value Store an even more powerful tool.
The "Serverless" State Problem
In the App Router, your components run on the server.
- Layouts: Run on the server.
- Pages: Run on the server.
- Actions: Run on the server.
But "The Server" is often a serverless function (Vercel, AWS Lambda). It has no persistent memory. You can't just save global.userCache = {}.
BaseKV + Next.js: The Perfect Match
You need a database that acts like a global memory. Because BaseKV supports HTTP connections (via standard fetch or client libraries), it is firewall-friendly and works perfectly in edge environments.
Patterns
1. Caching API Responses (Memoization)
Don't hit your slow CMS on every request. Cache it.
// app/blog/[slug]/page.tsx
import { redis } from '@/lib/db';
export default async function BlogPost({ params }) {
const cacheKey = `post:${params.slug}`;
// 1. Try Cache
let post = await redis.get(cacheKey);
if (!post) {
// 2. Fetch Source
post = await fetchFromCMS(params.slug);
// 3. Save to KV (expire in 1 hour)
await redis.set(cacheKey, JSON.stringify(post), 'EX', 3600);
} else {
post = JSON.parse(post);
}
return <Article data={post} />;
}
2. Rate Limiting Server Actions
Prevent abuse of your forms.
// app/actions.ts
'use server'
import { redis } from '@/lib/db';
import { headers } from 'next/headers';
export async function submitComment(formData: FormData) {
const ip = headers().get('x-forwarded-for') || '127.0.0.1';
const key = `ratelimit:${ip}`;
const count = await redis.incr(key);
if (count === 1) {
await redis.expire(key, 60); // Reset every minute
}
if (count > 5) {
throw new Error("Too many requests!");
}
// process comment...
}
Why not just use unstable_cache?
Next.js has a built-in Data Cache. It's great for static data. But for dynamic user data (like sessions, rate limits, shopping carts, feature flags), you need a real database that gives you:
- Atomic increments (
INCR). - Immediate consistency (no stale-while-revalidate lag).
- Persistence beyond the build cache.
Conclusion
A Key-Value store is the missing "State/Memory" layer for your stateless Next.js application. It enables patterns that static caching cannot handle.
supercharge your Next.js app with BaseKV.