Tutoriels

Next.js rewrites : servir un blog sous /blog (guide complet)

Comment utiliser les rewrites de Next.js pour afficher un blog externe sous votre /blog sans changer d'URL : syntaxe, ordre d'évaluation, pièges SEO et vérifications.

Bloglet
· 6 min de lecture

PartagerXin

Vous voulez afficher un blog sous monsite.com/blog, mais ce blog est hébergé ailleurs ? Dans une application Next.js, la solution tient en quelques lignes : les rewrites.

Ce guide explique comment elles fonctionnent, comment les écrire pour servir un blog externe sous /blog, et surtout comment éviter les pièges qui cassent le rendu ou le référencement.

Rewrite ou redirection : la différence

Les deux paraissent proches, mais leur effet est opposé.

RewriteRedirection
URL affichée dans le navigateurNe change pasChange
Ce que voit le visiteurLe contenu d'une autre adresse, sous votre URLUne nouvelle page, à une nouvelle URL
Usage typiqueServir un blog externe sous /blog, renommer une route en interneDéplacer une page, migrer un ancien site

Une rewrite fonctionne comme un proxy : Next.js va chercher le contenu à une autre adresse et le renvoie tel quel, sous l'URL demandée. Pour Google comme pour vos lecteurs, la page vit bien sur monsite.com/blog. C'est exactement ce qu'il faut pour qu'un blog renforce votre domaine (voir Blog en sous-domaine ou en /blog : lequel choisir pour le SEO ?).

La syntaxe de base

Les rewrites se déclarent dans next.config.ts, avec une fonction rewrites() qui renvoie une liste de règles. Chaque règle a une source (l'adresse demandée sur votre site) et une destination (l'adresse dont on affiche le contenu).

ts
// next.config.ts
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  async rewrites() {
    return [
      { source: "/a-propos", destination: "/about" },
    ]
  },
}

export default nextConfig

Ici, monsite.com/a-propos affiche le contenu de la page /about, sans que l'URL ne change.

Les motifs de chemin

La source accepte des paramètres, que l'on peut réutiliser dans la destination :

  • /blog/:slug correspond à /blog/mon-article, mais pas à /blog/a/b ;
  • /blog/:path* correspond à /blog, /blog/mon-article et /blog/a/b/c (le * signifie « zéro ou plusieurs segments ») ;
  • /blog/:id(\\d+) ne correspond qu'aux identifiants numériques, grâce à une expression régulière.
ts
{ source: "/blog/:path*", destination: "https://exemple.com/blog/:path*" }

Le paramètre :path* capture tout ce qui suit /blog et le recopie dans la destination.

Servir un blog externe sous /blog

C'est le cas le plus courant : votre site est en Next.js, votre blog est hébergé par un autre service, et vous voulez qu'il s'affiche sous votre domaine. La destination peut tout à fait être une URL externe.

Voici la configuration utilisée par bloglet :

ts
// next.config.ts
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  async rewrites() {
    return [
      { source: "/blog", destination: "https://bloglet.app/monsite/blog" },
      { source: "/blog/:path*", destination: "https://bloglet.app/monsite/blog/:path*" },
      { source: "/rss.xml", destination: "https://bloglet.app/monsite/rss.xml" },
      { source: "/blog-sitemap.xml", destination: "https://bloglet.app/monsite/sitemap.xml" },
    ]
  },
}

export default nextConfig

Ligne par ligne :

  1. /blog affiche la liste des articles.
  2. /blog/:path* affiche chaque article (/blog/mon-article).
  3. /rss.xml sert le flux RSS sous votre domaine.
  4. /blog-sitemap.xml sert le sitemap des articles, pour que Google les découvre.

Techniquement, la règle /blog/:path* couvre aussi /blog. Garder les deux lignes rend simplement la configuration plus lisible.

Si votre next.config.ts contient déjà une fonction rewrites(), ajoutez ces lignes au tableau existant plutôt que d'en créer une seconde.

Déclarer le sitemap du blog

Pour que Google trouve vos articles rapidement, ajoutez le sitemap du blog à votre fichier robots :

ts
// app/robots.ts
import type { MetadataRoute } from "next"

export default function robots(): MetadataRoute.Robots {
  return {
    rules: { userAgent: "*", allow: "/" },
    sitemap: [
      "https://monsite.com/sitemap.xml",
      "https://monsite.com/blog-sitemap.xml",
    ],
  }
}

Vous pouvez aussi le déclarer directement dans Google Search Console, rubrique Sitemaps.

L'ordre d'évaluation : le piège numéro un

Quand rewrites() renvoie un simple tableau, Next.js applique les règles après avoir vérifié vos fichiers et vos pages, mais avant les routes dynamiques (documentation Next.js).

Conséquence directe : si votre projet contient déjà une page app/blog/page.tsx, c'est elle qui s'affiche, et votre rewrite vers le blog externe est ignorée. Deux solutions :

  • supprimer l'ancienne route /blog de votre projet (la plus simple) ;
  • ou placer vos règles dans beforeFiles, qui passe avant les fichiers et les pages :
ts
async rewrites() {
  return {
    beforeFiles: [
      { source: "/blog/:path*", destination: "https://bloglet.app/monsite/blog/:path*" },
    ],
  }
}

La fonction peut en effet renvoyer un objet avec trois listes :

  • beforeFiles : appliquées avant les fichiers et les pages ;
  • afterFiles : appliquées après les pages, avant les routes dynamiques (c'est le comportement du simple tableau) ;
  • fallback : appliquées en dernier, juste avant la page 404. Pratique pour migrer progressivement un ancien site vers Next.js.

Les autres pièges fréquents

trailingSlash: true

Si votre site utilise trailingSlash: true, ajoutez la barre finale dans la source, et dans la destination si le serveur de destination l'attend aussi :

ts
{ source: "/blog/:path*/", destination: "https://exemple.com/blog/:path*/" }

basePath

Avec un basePath (par exemple /app), Next.js préfixe automatiquement la source et la destination. Pour une rewrite externe qui ne doit pas être préfixée, ajoutez basePath: false à la règle.

Les ressources du blog distant

La page renvoyée par la rewrite est affichée sous votre domaine. Si elle charge ses feuilles de style, scripts ou images avec des chemins relatifs, le navigateur les cherchera… sur votre site, où ils n'existent pas. Le blog distant doit donc utiliser des URL absolues pour ses ressources. C'est l'une des raisons de passer par un service prévu pour être servi sous votre domaine plutôt que de proxifier n'importe quel site.

L'URL canonique

C'est le point le plus important pour le SEO. Le même article est accessible à deux adresses : monsite.com/blog/mon-article et l'adresse d'origine chez l'hébergeur. Pour éviter le contenu dupliqué, la page doit déclarer comme URL canonique celle de votre domaine :

html
<link rel="canonical" href="https://monsite.com/blog/mon-article" />

Vérifiez-le dans le code source de la page. Un blog qui annonce sa propre adresse d'origine comme canonique fera travailler votre contenu pour un autre domaine.

Conditions avancées : has et missing

Une règle peut ne s'appliquer que si un en-tête, un cookie, un paramètre d'URL ou un nom de domaine correspond. Par exemple, pour ne servir le blog que sur votre domaine principal :

ts
{
  source: "/blog/:path*",
  has: [{ type: "host", value: "monsite.com" }],
  destination: "https://bloglet.app/monsite/blog/:path*",
}

missing fonctionne à l'inverse : la règle s'applique si l'élément est absent.

Et avec proxy.ts ?

Depuis Next.js 16, l'ancien fichier middleware.ts s'appelle proxy.ts (documentation). Il permet lui aussi de faire des rewrites, avec du code :

ts
// proxy.ts
import { NextResponse, type NextRequest } from "next/server"

export function proxy(request: NextRequest) {
  const { pathname, search } = request.nextUrl
  // /blog/mon-article → https://bloglet.app/monsite/blog/mon-article
  return NextResponse.rewrite(new URL(`/monsite${pathname}${search}`, "https://bloglet.app"))
}

export const config = {
  matcher: ["/blog", "/blog/:path*"],
}

C'est utile quand la règle dépend d'une logique dynamique (langue, test A/B, utilisateur connecté). Pour servir un blog sous /blog, les rewrites de next.config.ts suffisent, et Next.js recommande d'ailleurs de ne recourir au proxy qu'en dernier ressort.

Vérifier que tout fonctionne

Une fois déployé :

  1. Ouvrez monsite.com/blog : la liste des articles s'affiche, et l'URL reste celle de votre site.
  2. Vérifiez le statut HTTP dans un terminal :
bash
curl -I https://monsite.com/blog

La réponse doit commencer par HTTP/2 200, et non par une redirection (301, 302, 307 ou 308).

  1. Affichez le code source d'un article et cherchez rel="canonical" : l'adresse doit être sous votre domaine.
  2. Ouvrez monsite.com/blog-sitemap.xml : les URL listées doivent, elles aussi, être sous votre domaine.
  3. Testez une URL d'article avec l'outil d'inspection d'URL de Google Search Console.

Et si mon site n'est pas en Next.js ?

Si votre site est hébergé sur Vercel sans Next.js, les mêmes règles peuvent se déclarer dans un fichier vercel.json :

json
{
  "rewrites": [
    { "source": "/blog/:path*", "destination": "https://bloglet.app/monsite/blog/:path*" }
  ]
}

D'autres hébergeurs (Netlify, Cloudflare, Nginx…) proposent des mécanismes équivalents, avec leur propre syntaxe.

En résumé

  • Une rewrite affiche le contenu d'une autre adresse sans changer l'URL : idéal pour servir un blog externe sous /blog.
  • La destination peut être une URL externe, et :path* recopie la suite du chemin.
  • Une page /blog existante dans votre projet passe avant les rewrites : supprimez-la ou utilisez beforeFiles.
  • Le blog distant doit utiliser des URL absolues pour ses ressources et déclarer votre domaine comme URL canonique.
  • Déclarez le sitemap du blog dans robots.ts ou dans Search Console.

Avec bloglet, les quatre lignes de rewrites suffisent : le rendu serveur, les balises SEO, l'URL canonique sous votre domaine, le sitemap et le flux RSS sont déjà gérés. Suivez le guide complet ou créez votre blog gratuitement.

Écrit par Bloglet
Retrouvez tous nos articles sur le blog de Bloglet.