Prendre RDVContact
Retour à toutes les notes
1 juin 2026

Implémenter la mise en cache Redis pour les applications Next.js 15

Next.js 15App RouterServer ComponentREDIS2ms LatencyRedis.get()Cache Hit

Implémenter la mise en cache Redis pour les applications Next.js 15

Next.js 15 propose des stratégies de cache agressives par défaut, mais s'appuyer uniquement sur le cache système local ou sur le cache mémoire pour des applications d'entreprise est une recette idéale pour obtenir des données obsolètes, des performances instables et des difficultés de déploiement. Lorsque vous distribuez votre application sur plusieurs fonctions serverless ou conteneurs, le cache local ne suffit plus. Il vous faut un cache distribué. Il vous faut Redis.

Ce guide décrit précisément l'implémentation du cache Redis pour vos applications Next.js 15. Nous allons concevoir une architecture robuste et évolutive à l'aide d'Upstash Redis (ou de tout autre fournisseur Redis) et de l'API native unstable_cache de Next.js, en contournant les réglages par défaut fragiles pour reprendre le contrôle de votre couche de données.

Le problème

Next.js 15 repose fortement sur le cache de la Fetch API et sur le cache des segments de route. Par défaut, il stocke les données mises en cache sur le système de fichiers local. Cela fonctionne très bien pour un site statique hébergé sur une seule instance Node.js.

Cependant, lorsque vous déployez votre application sur des plateformes serverless telles que Vercel ou AWS Lambda, votre application s'adapte à la charge en démarrant plusieurs instances indépendantes. L'Instance A n'a pas accès au cache système de l'Instance B. Si un utilisateur interroge l'Instance A, il obtiendra des données fraîches. S'il interroge l'Instance B, il risque d'obtenir des données obsolètes ou de déclencher une requête redondante vers la base de données.

De plus, le cache du système de fichiers est éphémère. Déployer une nouvelle version de votre application vide généralement l'intégralité du cache, provoquant des pics de trafic massifs sur votre base de données immédiatement après le déploiement (phénomène de cache stampede ou ruée sur le cache).

Il nous faut un cache persistant et distribué, externe au code de l'application et capable de survivre aux déploiements.

Pourquoi c'est difficile

Intégrer Redis dans Next.js ne se résume pas à appeler redis.get() et redis.set(). Next.js 15 repose sur une architecture de composants serveur React (React Server Components - RSC) bien définie. Le framework cherche à superviser lui-même la couche de cache.

Si vous encapsulez simplement vos appels de base de données dans des commandes Redis, vous allez à l'encontre du fonctionnement du framework. Vous perdez le bénéfice de la révalidation à la demande (revalidateTag, revalidatePath) et vous risquez de transmettre des données incohérentes au client.

Le défi consiste à insérer Redis dans le cycle de vie du cache de Next.js. Nous devons intercepter les lectures et écritures de cache du framework, en remplaçant de manière transparente le cache éphémère du système de fichiers par notre stockage distribué Redis, tout en conservant la compatibilité avec les fonctions de révalidation de Next.js.

Cela nécessite l'usage de gestionnaires de cache personnalisés (cache handlers), une fonctionnalité qui a longtemps conservé un statut expérimental dans Next.js. Dans Next.js 15, la configuration d'un gestionnaire de cache personnalisé est la seule option viable pour les applications à fort trafic.

Architecture

Notre architecture s'articule autour de trois couches :

  1. La couche application (Next.js 15) : Les React Server Components exécutent la logique métier et génèrent l'interface utilisateur.
  2. L'intercepteur de cache : Un gestionnaire de cache Next.js personnalisé qui intercepte les requêtes unstable_cache et fetch.
  3. La couche de cache distribué (Redis) : Un stockage clé-valeur en mémoire rapide qui héberge les réponses sérialisées.

Lorsqu'un Server Component demande des données :

  1. Le framework sollicite notre gestionnaire de cache personnalisé.
  2. Le gestionnaire vérifie la présence de la clé dans Redis.
  3. En cas de succès (cache hit), nous désérialisons le JSON et le retournons. Le framework génère immédiatement l'interface utilisateur.
  4. En cas d'échec (cache miss), le framework exécute la logique de récupération de données (par exemple, une requête PostgreSQL), transmet le résultat à notre gestionnaire, qui l'écrit dans Redis avant de le retourner au composant.

Cela garantit que toutes les instances serverless partagent une source de vérité unique.

Implémentation

Nous allons utiliser le package @neshca/cache-handler. Il fournit une base robuste et prête pour la production pour les gestionnaires de cache personnalisés Next.js, spécialement conçue pour s'interfacer avec Redis. Nous utiliserons ioredis comme client Redis.

1. Installer les dépendances

npm install @neshca/cache-handler ioredis

2. Configurer le client Redis

Créez une instance de client Redis robuste. N'initialisez pas plusieurs connexions par invocation serverless.

// lib/redis.ts
import { Redis } from 'ioredis';

const redisUrl = process.env.REDIS_URL;

if (!redisUrl) {
  throw new Error('REDIS_URL environment variable is not defined');
}

// Assurer une instance unique en développement pour éviter les fuites de connexion lors du HMR (Hot Module Replacement)
const globalForRedis = global as unknown as { redis: Redis };

export const redis = globalForRedis.redis || new Redis(redisUrl, {
  maxRetriesPerRequest: 3,
  enableReadyCheck: false,
});

if (process.env.NODE_ENV !== 'production') globalForRedis.redis = redis;

3. Créer le gestionnaire de cache

Ce fichier indique à Next.js comment communiquer avec Redis. Il fait correspondre les opérations de cache de Next.js (get, set, revalidateTag) aux commandes Redis.

// cache-handler.mjs
import { CacheHandler } from '@neshca/cache-handler';
import createRedisHandler from '@neshca/cache-handler/redis-strings';
import { Redis } from 'ioredis';

CacheHandler.onCreation(async () => {
  let client;

  try {
    // Instanciation du client.
    // En production, assurez-vous que REDIS_URL est défini.
    client = new Redis(process.env.REDIS_URL, {
      maxRetriesPerRequest: 3,
      lazyConnect: true, // N'interrompt pas le démarrage
    });
    
    // Test de la connexion
    client.on('error', (error) => {
      console.error('Erreur de connexion Redis :', error);
    });

  } catch (error) {
    console.warn('Échec de l\'initialisation du client Redis pour le gestionnaire de cache', error);
  }

  return {
    handlers: [
      createRedisHandler({
        client,
        keyPrefix: 'next-cache:',
        timeoutMs: 1000, // Échoue rapidement si Redis est ralenti
      }),
    ],
  };
});

export default CacheHandler;

4. Intégration dans Next.js

Indiquez à Next.js d'utiliser votre gestionnaire de cache personnalisé dans next.config.js.

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    // Note : les fonctionnalités expérimentales évoluent, mais c'est la structure actuelle pour Next 15
    cacheHandler: require.resolve('./cache-handler.mjs'),
    cacheLife: {
      default: {
        stale: 3600, // 1 heure
        revalidate: 86400, // 1 jour
      },
    },
  },
};

module.exports = nextConfig;

5. Récupération des données

Utilisez désormais unstable_cache ou la fonction native fetch comme d'habitude. Le framework achemine de manière transparente la mise en cache via Redis.

// app/products/[id]/page.tsx
import { unstable_cache } from 'next/cache';
import { db } from '@/lib/db';

const getProduct = unstable_cache(
  async (id: string) => {
    console.log('Cache miss : Récupération du produit depuis la base de données', id);
    return await db.product.findUnique({ where: { id } });
  },
  ['product-details'], // Segments de clé de cache
  { tags: ['products'], revalidate: 3600 } 
);

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await getProduct(params.id);

  if (!product) return <div>Produit non trouvé</div>;

  return (
    <main>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </main>
  );
}

Lorsque vous devez invalider ces données (par exemple, via un webhook de panneau d'administration), appelez simplement revalidateTag('products'). Le gestionnaire de cache traduit cette action en une commande Redis DEL ou une invalidation basée sur les tags, garantissant que la requête suivante interroge la base de données.

Pièges à éviter

La mise en œuvre du cache Redis dans Next.js 15 peut vous confronter à plusieurs pièges architecturaux. Évitez les erreurs suivantes.

1. Latence de Redis et surcharges de requêtes (Timeout Storms)

Redis est extrêmement rapide, mais la latence réseau reste imprévisible. Si votre instance Redis s'arrête ou si la latence de connexion atteint 2000 ms, l'intégralité de votre application Next.js se bloquera en attendant le cache. Solution : Imposez des délais d'attente stricts dans votre gestionnaire de cache (par exemple, timeoutMs: 500). Si Redis ne répond pas dans les 500 ms, le gestionnaire de cache doit poursuivre en traitant la situation comme un cache miss et interroger la base de données. La disponibilité de l'application prime sur la performance du cache.

2. Sérialisation d'objets volumineux

Redis stocke des chaînes de caractères. Next.js sérialise vos données en JSON avant de les transmettre au gestionnaire de cache. Stocker des objets JSON massifs de 5 Mo représentant une table entière sans pagination saturera les entrées/sorties réseau de votre instance Redis et consommera d'importantes ressources CPU pour la sérialisation/désérialisation. Solution : Ne mettez en cache que le strict nécessaire. Filtrez vos requêtes de base de données. Évitez d'exécuter SELECT *. Ne récupérez que les champs requis par le composant pour limiter la taille de la charge utile.

3. Ruées sur le cache (Cache Stampedes)

Lorsqu'une clé de cache populaire expire ou est invalidée, des centaines de requêtes simultanées peuvent interroger le serveur en même temps. Elles subiront toutes un cache miss et interrogeront simultanément la base de données pour la même requête, risquant de saturer votre base principale. Solution : La fonction unstable_cache de Next.js gère par défaut la déduplication des requêtes par instance. Pour une déduplication distribuée, vous devez implémenter un mécanisme de verrouillage basé sur Redis ou vous appuyer sur des modèles de type stale-while-revalidate (SWR), afin que l'utilisateur reçoive des données temporairement obsolètes le temps que la révalidation s'effectue en arrière-plan.

4. Fuites de connexions en environnement Serverless

Les environnements serverless (comme les fonctions Vercel) figent et réactivent les contextes d'exécution. Si vous ouvrez une nouvelle connexion Redis à chaque requête, vous dépasserez instantanément la limite de connexions autorisée par votre instance Redis. Solution : Instanciez le client Redis en dehors de la fonction de traitement des requêtes. Utilisez des clients Redis basés sur HTTP (comme l'API REST d'Upstash) si vous ne pouvez pas maintenir de connexions TCP persistantes, bien que @neshca/cache-handler gère très bien les clients persistants s'ils sont correctement configurés.

Résultat

En implémentant un gestionnaire de cache Redis personnalisé, vous remplacez le cache éphémère et imprévisible du système de fichiers par un stockage de données robuste et centralisé.

Vos déploiements ne vident plus le cache. Vos instances serverless partagent une source de vérité unique. La charge sur votre base de données diminue sensiblement et vos temps de réponse se stabilisent sur l'ensemble de votre infrastructure.

Next.js 15 gère la mise en cache. Laissez-lui le contrôle de l'API. Mais vous devez rester maître de votre infrastructure. Redis vous apporte le contrôle indispensable pour faire fonctionner Next.js à grande échelle. Ne vous contentez pas des configurations par défaut.

Service Seven Labs

Développement SaaS - Next.js & MERN

Nous construisons des applications Next.js. Voir nos services SaaS →
Loading...

Lire la suite

How VAPT Audits Prevent Enterprise Disaster

Discover how VAPT audits prevent enterprise disaster by exposing critical vulnerabilities before the...

Lire l'article

Automating CI/CD Pipelines with AI Code Reviewers

Automating CI/CD Pipelines with AI Code Reviewers is not just a buzzword. It's a fundamental shift i...

Lire l'article
Chat with us