Réécritures (rewrites)

Les réécritures vous permettent de mapper un chemin de requête entrant vers un chemin de destination différent.

Les réécritures agissent comme un proxy d'URL et masquent le chemin de destination, donnant l'impression que l'utilisateur n'a pas changé d'emplacement sur le site. En revanche, les redirections redirigeront vers une nouvelle page et afficheront les changements d'URL.

Pour utiliser les réécritures, vous pouvez utiliser la clé rewrites dans next.config.js :

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/about',
        destination: '/',
      },
    ]
  },
}

Les réécritures sont appliquées au routage côté client. Un <Link href="/about"> aura la réécriture appliquée dans l'exemple ci-dessus.

rewrites est une fonction asynchrone qui doit retourner soit un tableau, soit un objet de tableaux (voir ci-dessous) contenant des objets avec les propriétés source et destination :

  • source : String - le motif du chemin de requête entrant.
  • destination : String - le chemin vers lequel vous souhaitez router.
  • basePath : false ou undefined - si false, le basePath ne sera pas inclus lors de la correspondance, peut être utilisé uniquement pour les réécritures externes.
  • locale : false ou undefined - indique si la locale ne doit pas être incluse lors de la correspondance.
  • has est un tableau d'objets has avec les propriétés type, key et value.
  • missing est un tableau d'objets missing avec les propriétés type, key et value.

Lorsque la fonction rewrites retourne un tableau, les réécritures sont appliquées après la vérification du système de fichiers (pages et fichiers /public) et avant les routes dynamiques. Lorsque la fonction rewrites retourne un objet de tableaux avec une forme spécifique, ce comportement peut être modifié et contrôlé plus finement, à partir de v10.1 de Next.js :

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // Ces réécritures sont vérifiées après les en-têtes/redirections
        // et avant tous les fichiers, y compris les fichiers _next/public, ce qui
        // permet de remplacer les fichiers de page
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // Ces réécritures sont vérifiées après les fichiers pages/public
        // mais avant les routes dynamiques
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // Ces réécritures sont vérifiées après les fichiers pages/public
        // et les routes dynamiques
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

Bon à savoir : les réécritures dans beforeFiles ne vérifient pas immédiatement le système de fichiers/les routes dynamiques après avoir trouvé une correspondance pour une source, elles continuent jusqu'à ce que toutes les beforeFiles aient été vérifiées.

L'ordre dans lequel Next.js vérifie les routes est :

  1. Les en-têtes sont vérifiés/appliqués
  2. Les redirections sont vérifiées/appliquées
  3. Les réécritures beforeFiles sont vérifiées/appliquées
  4. Les fichiers statiques du répertoire public, les fichiers _next/static et les pages non dynamiques sont vérifiés/servis
  5. Les réécritures afterFiles sont vérifiées/appliquées ; si l'une de ces réécritures correspond, nous vérifions les routes dynamiques/fichiers statiques après chaque correspondance
  6. Les réécritures fallback sont vérifiées/appliquées ; elles sont appliquées avant le rendu de la page 404 et après la vérification des routes dynamiques/tous les actifs statiques. Si vous utilisez fallback: true/'blocking' dans getStaticPaths, les réécritures fallback définies dans votre next.config.js ne seront pas exécutées.

Paramètres de réécriture

Lorsque vous utilisez des paramètres dans une réécriture, les paramètres seront passés dans la requête par défaut lorsqu'aucun des paramètres n'est utilisé dans la destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // Le paramètre :path n'est pas utilisé ici, donc il sera automatiquement passé dans la requête
      },
    ]
  },
}

Si un paramètre est utilisé dans la destination, aucun des paramètres ne sera automatiquement passé dans la requête.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // Le paramètre :path est utilisé ici, donc il ne sera pas automatiquement passé dans la requête
      },
    ]
  },
}

Vous pouvez toujours passer les paramètres manuellement dans la requête si l'un est déjà utilisé dans la destination en spécifiant la requête dans la destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // Comme le paramètre :first est utilisé dans la destination, le paramètre :second
        // ne sera pas automatiquement ajouté dans la requête, bien que nous puissions l'ajouter manuellement
        // comme montré ci-dessus
      },
    ]
  },
}

Bon à savoir : Les pages statiques de l'Optimisation Statique Automatique ou les paramètres de prérendu des réécritures seront analysés côté client après l'hydratation et fournis dans la requête.

Correspondance de chemin

Les correspondances de chemin sont autorisées, par exemple /blog/:slug correspondra à /blog/hello-world (pas de chemins imbriqués) :

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // Les paramètres correspondants peuvent être utilisés dans la destination
      },
    ]
  },
}

Correspondance de chemin avec joker

Pour correspondre à un chemin avec joker, vous pouvez utiliser * après un paramètre, par exemple /blog/:slug* correspondra à /blog/a/b/c/d/hello-world :

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // Les paramètres correspondants peuvent être utilisés dans la destination
      },
    ]
  },
}

Correspondance de chemin avec regex

Pour correspondre à un chemin avec regex, vous pouvez encapsuler la regex entre parenthèses après un paramètre, par exemple /blog/:slug(\\d{1,}) correspondra à /blog/123 mais pas à /blog/abc :

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // Les paramètres correspondants peuvent être utilisés dans la destination
      },
    ]
  },
}

Les caractères suivants (, ), {, }, [, ], |, \, ^, ., :, *, +, -, ?, $ sont utilisés pour la correspondance de chemin regex, donc lorsqu'ils sont utilisés dans la source comme valeurs non spéciales, ils doivent être échappés en ajoutant \\ avant eux :

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // cela correspondra à `/english(default)/something` demandé
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

Pour ne correspondre à une réécriture que lorsque les valeurs d'en-tête, de cookie ou de requête correspondent également, le champ has peut être utilisé, ou le champ missing pour les valeurs qui ne doivent pas correspondre. À la fois la source et tous les éléments has doivent correspondre, et tous les éléments missing ne doivent pas correspondre pour que la réécriture soit appliquée.

Les éléments has et missing peuvent avoir les champs suivants :

  • type : String - doit être soit header, cookie, host ou query.
  • key : String - la clé du type sélectionné à comparer.
  • value : String ou undefined - la valeur à vérifier, si undefined n'importe quelle valeur correspondra. Une chaîne de type regex peut être utilisée pour capturer une partie spécifique de la valeur, par exemple si la valeur first-(?<paramName>.*) est utilisée pour first-second, alors second pourra être utilisé dans la destination avec :paramName.
next.config.js
module.exports = {
  async rewrites() {
    return [
      // si l'en-tête `x-rewrite-me` est présent,
      // cette réécriture sera appliquée
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // si l'en-tête `x-rewrite-me` n'est pas présent,
      // cette réécriture sera appliquée
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // si la source, la requête et le cookie correspondent,
      // cette réécriture sera appliquée
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // la valeur de page ne sera pas disponible dans la
            // destination car la valeur est fournie et n'utilise pas
            // un groupe de capture nommé, par exemple (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // si l'en-tête `x-authorized` est présent et
      // contient une valeur correspondante, cette réécriture sera appliquée
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // si l'hôte est `example.com`,
      // cette réécriture sera appliquée
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

Réécriture vers une URL externe

Exemples

Les réécritures vous permettent de réécrire vers une URL externe. Ceci est particulièrement utile pour adopter Next.js de manière progressive. Voici un exemple de réécriture pour rediriger la route /blog de votre application principale vers un site externe.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog',
        destination: 'https://example.com/blog',
      },
      {
        source: '/blog/:slug',
        destination: 'https://example.com/blog/:slug', // Les paramètres correspondants peuvent être utilisés dans la destination
      },
    ]
  },
}

Si vous utilisez trailingSlash: true, vous devez également insérer une barre oblique à la fin dans le paramètre source. Si le serveur de destination attend également une barre oblique à la fin, elle doit être incluse dans le paramètre destination.

next.config.js
module.exports = {
  trailingSlash: true,
  async rewrites() {
    return [
      {
        source: '/blog/',
        destination: 'https://example.com/blog/',
      },
      {
        source: '/blog/:path*/',
        destination: 'https://example.com/blog/:path*/',
      },
    ]
  },
}

Adoption progressive de Next.js

Vous pouvez également faire en sorte que Next.js se rabatte sur un proxy vers un site web existant après avoir vérifié toutes les routes Next.js.

De cette façon, vous n'avez pas besoin de modifier la configuration des réécritures lorsque vous migrez plus de pages vers Next.js.

next.config.js
module.exports = {
  async rewrites() {
    return {
      fallback: [
        {
          source: '/:path*',
          destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
        },
      ],
    }
  },
}

Réécritures avec support de basePath

Lorsque vous utilisez le support de basePath avec des réécritures, chaque source et destination est automatiquement préfixé avec le basePath sauf si vous ajoutez basePath: false à la réécriture :

next.config.js
module.exports = {
  basePath: '/docs',

  async rewrites() {
    return [
      {
        source: '/with-basePath', // devient automatiquement /docs/with-basePath
        destination: '/another', // devient automatiquement /docs/another
      },
      {
        // n'ajoute pas /docs à /without-basePath car basePath: false est défini
        // Note : ceci ne peut pas être utilisé pour les réécritures internes, par exemple `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

Réécritures avec support i18n

Lorsque vous utilisez le support i18n avec des réécritures, chaque source et destination est automatiquement préfixé pour gérer les locales configurées, sauf si vous ajoutez locale: false à la réécriture. Si locale: false est utilisé, vous devez préfixer la source et la destination avec une locale pour qu'elle corresponde correctement.

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },

  async rewrites() {
    return [
      {
        source: '/with-locale', // gère automatiquement toutes les locales
        destination: '/another', // passe automatiquement la locale
      },
      {
        // ne gère pas les locales automatiquement car locale: false est défini
        source: '/nl/with-locale-manual',
        destination: '/nl/another',
        locale: false,
      },
      {
        // cela correspond à '/' car `en` est la defaultLocale
        source: '/en',
        destination: '/en/another',
        locale: false,
      },
      {
        // il est possible de correspondre à toutes les locales même lorsque locale: false est défini
        source: '/:locale/api-alias/:path*',
        destination: '/api/:path*',
        locale: false,
      },
      {
        // cela est converti en /(en|fr|de)/(.*) donc ne correspondra pas aux routes
        // de premier niveau `/` ou `/fr` comme /:path* le ferait
        source: '/(.*)',
        destination: '/another',
      },
    ]
  },
}

Historique des versions

VersionChangements
v13.3.0Ajout de missing.
v10.2.0Ajout de has.
v9.5.0Ajout des en-têtes.