Next.js Edge Middleware Caching

The missing fetch() cache
for Next.js middleware on Vercel.

A Next.js fetch wrapper for edge middleware that uses Vercel Runtime Cache as its caching backend. Drop-in replacement with SWR support, GraphQL compatibility, and zero configuration.

SWR Caching

Stale-while-revalidate strategy with background refresh using waitUntil()

Drop-in Replacement

Works exactly like Next.js fetch with cache, next.revalidate, and next.tags

Performance Insights

Cache status headers with HIT/MISS/STALE indicators and timing data

Everything you need for middleware caching

Built specifically for Next.js edge middleware with all the features you expect from modern caching solutions.

Performance
SWR Caching Strategy
Implements stale-while-revalidate using Vercel's waitUntil() for non-blocking background refresh.
Infrastructure
Vercel Runtime Cache
Uses Vercel's Runtime Cache as the backend storage, providing persistence across requests.
Developer Experience
Drop-in Replacement
Works exactly like Next.js fetch with support for cache, next.revalidate, and next.tags options.
Debugging
Cache Status Headers
Get detailed cache information via X-Cache-Status, X-Cache-Age, and X-Cache-Expires-In headers.
API Support
GraphQL Support
Caches POST requests with different queries separately, perfect for GraphQL APIs.
Edge Computing
Edge Runtime Compatible
Designed specifically for Next.js Edge Runtime and middleware environments.
Reliability
Graceful Fallback
Falls back to regular fetch if cache operations fail, ensuring reliability.
Configuration
Flexible Expiry
Separate revalidation and expiry times for optimal cache management and performance.

Get started in seconds

Install the package and start caching your middleware requests immediately.

InstallationRequired
Choose your preferred package manager to install cached-middleware-fetch-next.
npm install cached-middleware-fetch-next
RequirementsInfo
Next.js 14.0.0 or later
@vercel/functions 2.2.13 or later
Deployed on Vercel ( Runtime Cache)
Environment BehaviorInfo

On Vercel Edge

Uses Runtime Cache with SWR

Local Development

Falls back to native fetch

Quick Start Guide

Get up and running with cached middleware fetch in just a few lines of code.

Basic UsageStep 1
Replace your regular fetch calls in middleware with cachedFetch for instant caching.
import { cachedFetch } from 'cached-middleware-fetch-next';
import { NextRequest, NextResponse } from 'next/server';

export async function middleware(request: NextRequest) {
  // This will be cached using Vercel Runtime Cache
  const response = await cachedFetch('https://api.example.com/data');
  const data = await response.json();

  // Use the data in your middleware logic
  return NextResponse.next();
}
With Caching OptionsStep 2
Use Next.js-style caching options for fine-grained control over cache behavior.
import { cachedFetch } from 'cached-middleware-fetch-next';

// Cache for 5 minutes with SWR behavior
const response = await cachedFetch('https://api.example.com/data', {
  next: { 
    revalidate: 300,  // Consider stale after 5 minutes
    expires: 3600     // Keep serving stale data for up to 1 hour
  }
});

// Check cache status
const cacheStatus = response.headers.get('X-Cache-Status'); // 'HIT' | 'MISS' | 'STALE'
const cacheAge = response.headers.get('X-Cache-Age');       // Age in seconds
Real-World ExampleStep 3
A practical example showing route resolution caching in middleware.
import { NextRequest, NextResponse } from 'next/server';
import { cachedFetch } from 'cached-middleware-fetch-next';

export async function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname;

  // Cache route resolution for 30 minutes
  const routeResponse = await cachedFetch(
    `https://api.example.com/routes?path=${pathname}`,
    {
      next: {
        revalidate: 1800, // 30 minutes
        tags: ['routes']
      }
    }
  );

  const route = await routeResponse.json();

  if (route.redirect) {
    return NextResponse.redirect(new URL(route.redirect, request.url));
  }

  if (route.rewrite) {
    return NextResponse.rewrite(new URL(route.rewrite, request.url));
  }

  return NextResponse.next();
}

Real-world Examples

See how to use cached-middleware-fetch-next in common scenarios and advanced use cases.

GraphQL SupportPOST Requests
Cache GraphQL queries with different variables separately for optimal performance.
// Each unique query gets its own cache entry
const response = await cachedFetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: `
      query GetProducts($category: String!) {
        products(category: $category) {
          id
          name
          price
        }
      }
    `,
    variables: { category: 'electronics' }
  }),
  next: {
    revalidate: 3600, // Cache for 1 hour
    tags: ['products', 'electronics']
  }
});

// Different variables = different cache key
const clothingResponse = await cachedFetch('https://api.example.com/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: `query GetProducts($category: String!) { ... }`,
    variables: { category: 'clothing' } // This gets cached separately
  }),
  next: { revalidate: 3600 }
});

API Reference

Complete reference for all functions, options, and return values.

cachedFetch(input, init?)Main Function
The primary function that replaces native fetch with caching capabilities.

Alternative ImportOptional
Import as 'fetch' for easier migration from existing code.
import { fetch } from 'cached-middleware-fetch-next';

// Now you can use it exactly like native fetch
const response = await fetch('https://api.example.com/data', {
  next: { revalidate: 300 }
});