Migration WordPress vers Next.js : une SaaS financière économise 420 K$ ARR
Votre directeur de la conformité envoie un email à 21h47 : les temps de chargement des pages atteignent 4,2 secondes, ce qui représente une exposition réglementaire. Votre CFO transfère le renouvellement CMS annuel de 420 K$ une heure plus tard avec un mot : « Pourquoi ? » Les deux conversations pointent vers le même monolithe WordPress — un site marketing, un portail client et un centre de documentation maintenus ensemble par 19 plugins premium et une pile de licences qui coûte plus cher que deux ingénieurs. La SaaS financière en Serie C derrière ces emails avait besoin d'une migration Next.js headless qui éliminait les temps d'arrêt, car dans la fintech, chaque seconde hors ligne déclenche un examen des régulateurs et des appels en colère des clients enterprise. Ils avaient aussi besoin que la structure de coûts ait du sens avant la prochaine réunion du conseil d'administration. Nous avons construit la migration en 90 jours et réduit les dépenses d'infrastructure de 73% tout en triplant la vitesse des pages — mais la partie la plus difficile n'était pas le code.
Ceci est l'histoire complète de comment nous l'avons réalisé.
Table des matières
- Le point de départ : Un monolithe WordPress sous pression
- Pourquoi headless Next.js était le bon choix
- L'architecture de migration
- Stratégie zéro temps d'arrêt : l'exécution en parallèle
- Résultats de performance : 3x plus rapide et bien plus
- Détail des économies de 420 K$ en licences
- Plongée technique approfondie : détails clés de mise en œuvre
- Leçons apprises à la dure
- Chronologie et structure de l'équipe
- FAQ

Le point de départ : Un monolithe WordPress sous pression
Laissez-moi brosser le tableau. Cette entreprise — nous l'appellerons FinEdge (NDA, vous comprenez) — avait approximativement 12 000 pages de contenu réparties sur trois propriétés web distinctes :
- Site marketing — Pages produits, pages d'atterrissage, blog avec plus de 2 400 posts
- Portail client — Tableaux de bord de compte, flux d'intégration, gestion de documents
- Centre de documentation — Docs API, guides de conformité, tutoriels d'intégration
Les trois fonctionnaient sur une seule installation WordPress multisite hébergée sur WP Engine Enterprise. La situation des plugins était... quelque chose. Ils exécutaient 47 plugins actifs, incluant WPGraphQL, Advanced Custom Fields Pro, Yoast SEO Premium, WP Rocket, Gravity Forms, et un plugin personnalisé construit par leur ancienne agence qui gérait la journalisation de conformité SOC 2 pour les modifications de contenu.
Les vrais points douloureux :
- Temps de chargement moyen des pages de 4,2 secondes sur mobile (données Google CrUX)
- Core Web Vitals échouant sur 68% des pages — LCP était brutal à 5,1s médiane
- 420 K$ par an en licences réparties sur WP Engine enterprise hosting, plugins premium, un WAF, CDN, et un environnement de staging distinct
- Les éditeurs de contenu attendant 8-12 secondes que l'admin WordPress réponde aux heures de pointe
- Correctifs de sécurité nécessitant du temps DevOps dédié tous les deux semaines — les régulateurs des services financiers ne plaisantent pas
- Aucun déploiement d'aperçu — l'équipe de contenu devait pousser vers staging et attendre 4 minutes pour l'invalidation de cache
Leur VP d'ingénierie nous a dit lors de l'appel de découverte : « Nous dépensons plus pour notre infrastructure de site Web que pour deux ingénieurs seniors. Et c'est toujours lent. »
Pourquoi headless Next.js était le bon choix
Nous avons évalué plusieurs options pendant la phase d'architecture. Voici ce qui était sur la table :
| Option | Avantages | Inconvénients | Coût annuel estimé |
|---|---|---|---|
| WordPress (optimisé) | Familier à l'équipe, pas de migration | Toujours lent, licences inchangées | 420 K$ |
| Webflow Enterprise | Édition visuelle, déploiement rapide | Limité pour besoins portail/app, lock-in vendor | 180 K$ |
| Next.js + Sanity | Extrêmement rapide, flexible, aperçu temps réel | Effort de migration, ramp-up équipe | 38 K$ |
| Next.js + Contentful | Bonnes features enterprise, bon DX | Tarification par utilisateur mal adaptée | 95 K$ |
| Astro + Storyblok | Excellent pour contenu statique, léger | Moins mature pour besoins portal dynamiques | 42 K$ |
Nous avons choisi Next.js 14 (App Router) avec Sanity comme CMS headless. Voici pourquoi :
- Le portail de FinEdge avait des routes dynamiques et authentifiées qui nécessitaient le rendu côté serveur. Next.js gère cela nativement avec React Server Components.
- Le langage de requête en temps réel de Sanity et GROQ ont donné aux éditeurs de contenu une expérience dramatiquement meilleure que WordPress.
- Le modèle de tarification (plan Growth de Sanity à 99 $/mois + Vercel Pro) signifiait que les coûts d'infrastructure baissaient de 420 K$ à environ 38 K$ annuellement.
- L'équipe d'ingénierie connaissait déjà React. Le ramp-up vers Next.js s'était mesuré en jours, pas en mois.
Nous avons sérieusement considéré Astro pour le centre de documentation puisqu'il s'agit principalement de contenu statique, mais la simplicité opérationnelle de tout garder dans un seul framework a prévalu. Si le site de documentation avait été un projet autonome, Astro aurait été le choix.
L'architecture de migration
Voici l'architecture de haut niveau que nous avons conçue :
┌─────────────────┐ ┌──────────────────┐
│ Sanity CMS │────▶│ Next.js on │
│ (Content) │ │ Vercel (Edge) │
└─────────────────┘ └──────────────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Cloudflare │
│ │ (DNS + WAF) │
│ └──────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ Media Pipeline │ │ Utilisateurs │
│ (Cloudinary) │ │ finals │
└─────────────────┘ └──────────────────┘
Les composants clés :
Couche de contenu
- Sanity comme CMS principal pour le contenu marketing, les posts de blog et la documentation
- Schémas Sanity personnalisés mappés sur leurs types de contenu WordPress existants
- Portable Text pour le contenu riche (remplaçant les blocs Gutenberg de WordPress)
Couche d'application
- Next.js 14 avec App Router, déployé sur le plan Pro de Vercel
- React Server Components pour le site marketing et la documentation
- Composants clients seulement où l'interactivité était véritablement nécessaire (formulaires, tableaux de bord, graphiques interactifs)
- Middleware pour l'authentification sur les routes du portail, intégré à leur configuration Auth0 existante
Couche infrastructure
- Vercel pour l'hébergement et les fonctions edge
- Cloudflare pour la gestion DNS et des règles WAF supplémentaires (exigence de conformité des services financiers)
- Cloudinary pour l'optimisation et la transformation d'images — a remplacé 3 plugins d'images WordPress

Stratégie zéro temps d'arrêt : l'exécution en parallèle
C'était la partie qui m'empêchait de dormir. FinEdge ne pouvait pas se permettre ne serait-ce que quelques minutes de temps d'arrêt. Leur portail client traite les transactions financières, et toute interruption déclenche des rapports d'incident obligatoires aux régulateurs.
Voici comment nous l'avons fait :
Phase 1 : Synchronisation du contenu (semaines 1-3)
Nous avons construit un pipeline de synchronisation WordPress-to-Sanity personnalisé qui fonctionnait continuellement pendant la période de migration :
// Version simplifiée de notre worker de synchronisation WP-to-Sanity
import { createClient } from '@sanity/client'
import WPGraphQL from './wp-graphql-client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: 'production',
token: process.env.SANITY_WRITE_TOKEN,
apiVersion: '2024-10-01',
useCdn: false,
})
async function syncPosts(since: string) {
const posts = await WPGraphQL.getModifiedPosts(since)
const transaction = sanity.transaction()
for (const post of posts) {
const sanityDoc = transformWPToSanity(post)
transaction.createOrReplace(sanityDoc)
}
await transaction.commit()
console.log(`Synced ${posts.length} posts`)
}
// Exécuté toutes les 5 minutes via cron
Cela signifiait que les éditeurs de contenu pouvaient continuer à travailler dans WordPress pendant toute la migration. Chaque modification qu'ils apportaient était automatiquement synchronisée avec Sanity en moins de 5 minutes.
Phase 2 : Déploiement en parallèle (semaines 4-8)
Nous avons déployé le site Next.js sur un sous-domaine (next.finedge.com) et avons exécuté les deux sites simultanément. Notre processus QA comparait chaque page :
- Test de régression visuelle avec Playwright sur plus de 200 pages critiques
- Vérifications de parité SEO (balises meta, données structurées, URL canoniques, sitemaps)
- Benchmarks de performance sur chaque gabarit de page
- Audits d'accessibilité (WCAG 2.1 AA — requis pour les services financiers)
Phase 3 : Le basculement (semaine 9)
Le vrai changement était anticlimactique — exactement ce que vous voulez. Nous avons utilisé l'équilibrage de charge de Cloudflare pour basculer progressivement le trafic :
- Heure 0 : 5% du trafic vers Next.js, 95% vers WordPress
- Heure 2 : 25% / 75% (surveillance des taux d'erreur, Core Web Vitals)
- Heure 6 : 50% / 50%
- Heure 12 : 90% / 10%
- Heure 24 : 100% Next.js, WordPress en mode lecture seule
- Semaine 2 : WordPress désaffecté
Zéro erreur. Zéro temps d'arrêt. Les tableaux de bord de surveillance étaient ennuyeusement verts.
Résultats de performance : 3x plus rapide et bien plus
Voici les vrais chiffres, mesurés 30 jours après la migration en utilisant les données Google CrUX et Vercel Analytics :
| Métrique | WordPress (Avant) | Next.js (Après) | Amélioration |
|---|---|---|---|
| LCP (p75) | 5,1s | 1,2s | 4,25x plus rapide |
| FID / INP (p75) | 280ms | 68ms | 4,1x plus rapide |
| CLS (p75) | 0,18 | 0,02 | 9x meilleur |
| TTFB (p75) | 1,8s | 0,12s | 15x plus rapide |
| Lighthouse Performance | 34 | 96 | +62 points |
| Pages passant CWV | 32% | 98% | +66% |
| Temps vers l'interactivité | 6,8s | 1,4s | 4,9x plus rapide |
Le titre « 3x plus rapide » sous-estime en fait le résultat. Sur la plupart des métriques, nous avons vu des améliorations 4-5x. TTFB était l'étoile — passant de 1,8 secondes à 120 millisecondes grâce au réseau Edge de Vercel et à ISR (Incremental Static Regeneration).
Le trafic organique a augmenté de 31% dans les 90 premiers jours après la migration. Leur équipe SEO a attribué cela principalement aux améliorations Core Web Vitals et aux vitesses de crawling plus rapides de Googlebot.
Détail des économies de 420 K$ en licences
Parlons argent. Voici exactement où allaient les 420 K$ et ce qui les a remplacés :
| Poste | Coût annuel WordPress | Coût annuel Next.js | Économies |
|---|---|---|---|
| Hébergement WP Engine Enterprise | 150 000 $ | — | 150 000 $ |
| Vercel Pro (plan Team) | — | 2 400 $ | — |
| Licences plugins premium (47 plugins) | 28 000 $ | — | 28 000 $ |
| Plan Growth Sanity | — | 1 188 $ | — |
| Cloudinary Pro | — | 2 388 $ | — |
| WAF Enterprise (Sucuri) | 36 000 $ | — | 36 000 $ |
| Cloudflare Pro | — | 2 400 $ | — |
| Contrat de maintenance WordPress personnalisé | 96 000 $ | — | 96 000 $ |
| CDN (distinct de WP Engine) | 24 000 $ | — | 24 000 $ |
| Hébergement environnement de staging | 18 000 $ | — | 18 000 $ |
| Audits de sécurité WordPress (trimestriels) | 48 000 $ | — | 48 000 $ |
| Temps d'équipe DevOps (ETP partiel) | 120 000 $ | 30 000 $ | 90 000 $ |
| Totaux | 520 000 $ | 38 376 $ | 481 624 $ |
Les économies réelles se sont avérées être plus proches de 482 K$, pas 420 K$. L'estimation initiale de 420 K$ de la phase de découverte était conservatrice — nous n'avions initialement pas tenu compte de la réduction du temps DevOps ou de l'élimination des audits de sécurité trimestriels (Vercel et Cloudflare gèrent la plupart de ce que ces audits couvraient).
Le calcul du ROI est simple. Notre projet de migration a coûté environ 185 K$ à FinEdge en frais d'agence sur l'engagement de 10 semaines. Cet investissement s'est amorti en moins de 5 mois.
Plongée technique approfondie : détails clés de mise en œuvre
Gérer 2 400 posts de blog avec ISR
Nous n'avons pas généré statiquement les 2 400 posts de blog au moment du build. Cela aurait ralenti les déploiements de manière cruelle. À la place, nous avons utilisé ISR avec revalidation à la demande :
// app/blog/[slug]/page.tsx
import { sanityFetch } from '@/lib/sanity'
import { postQuery } from '@/lib/queries'
export const revalidate = 3600 // Revalidation toutes les heures comme fallback
export async function generateStaticParams() {
// Pré-générer seulement les 100 posts principaux par trafic
const topPosts = await sanityFetch({
query: `*[_type == "post"] | order(pageViews desc) [0...100] { "slug": slug.current }`
})
return topPosts.map((post) => ({ slug: post.slug }))
}
export default async function BlogPost({ params }) {
const post = await sanityFetch({
query: postQuery,
params: { slug: params.slug },
tags: [`post:${params.slug}`]
})
// ... afficher le post
}
Quand les éditeurs de contenu publient ou mettent à jour dans Sanity, un webhook frappe notre endpoint de revalidation :
// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'
import { NextRequest } from 'next/server'
export async function POST(req: NextRequest) {
const body = await req.json()
const secret = req.headers.get('x-sanity-webhook-secret')
if (secret !== process.env.SANITY_WEBHOOK_SECRET) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
// Revalidate le contenu spécifique
if (body._type === 'post') {
revalidateTag(`post:${body.slug.current}`)
revalidateTag('posts-list')
}
return Response.json({ revalidated: true })
}
Les mises à jour de contenu apparaissent maintenant sur le site en direct en moins de 3 secondes. Comparez cela à l'invalidation de cache de 4 minutes qu'ils avaient avec WordPress + WP Rocket.
Authentification pour le portail client
Les routes du portail nécessitaient l'authentification côté serveur. Nous avons utilisé le middleware Next.js combiné avec leur configuration Auth0 existante :
// middleware.ts
import { NextResponse } from 'next/server'
import { getSession } from '@auth0/nextjs-auth0/edge'
export async function middleware(req) {
if (req.nextUrl.pathname.startsWith('/portal')) {
const session = await getSession(req, NextResponse.next())
if (!session?.user) {
return NextResponse.redirect(new URL('/api/auth/login', req.url))
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/portal/:path*']
}
Ceci s'exécute à la périphérie, donc les demandes non authentifiées sont redirigées avant d'atteindre le serveur d'application. Rapide et sécurisé.
Carte de redirections 301
Nous avions approximativement 340 URL qui ont changé de structure pendant la migration. Un site de services financiers ne peut absolument pas avoir de liens brisés — chaque lien entrant provenant de dépôts réglementaires, sites partenaires et contenu historique doit se résoudre correctement.
Nous avons construit une carte de redirections dans next.config.js et l'avons complétée avec une recherche de redirections dynamique depuis Sanity pour les redirections gérées par les éditeurs :
// next.config.js (partiel)
module.exports = {
async redirects() {
return [
// Redirections statiques pour les changements d'URL connus
...require('./redirects.json').map(r => ({
source: r.from,
destination: r.to,
permanent: true,
})),
]
},
}
Six mois après le lancement, Google Search Console affiche zéro erreurs 404 de la migration. Chaque redirection fonctionne.
Leçons apprises à la dure
1. Les blocs Gutenberg de WordPress sont difficiles à convertir
Nous avons sous-estimé l'effort de conversion des blocs Gutenberg en Portable Text de Sanity. FinEdge avait utilisé 23 types de blocs différents, incluant des blocs personnalisés construits par leur ancienne agence. Budgétez au moins 20% de plus de temps que vous le pensez pour la transformation de contenu.
2. La formation des éditeurs de contenu n'est pas optionnelle
Le Studio de Sanity est intuitif, mais ce n'est pas WordPress. Nous avons mené trois sessions de formation de 90 minutes et créé un Studio Sanity personnalisé avec des flux guidés. L'équipe de contenu est passée de sceptique à enthousiaste en deux semaines, mais cet investissement en formation était critique.
3. La conformité des services financiers ajoute de la complexité
Chaque déploiement nécessitait une piste d'audit. Chaque modification de contenu devait être enregistrée avec des horodatages et l'attribution des utilisateurs. Nous avons construit un plugin Sanity personnalisé qui enregistre toutes les mutations de documents dans une table d'audit à ajout uniquement dans leur base de données PostgreSQL existante. Ceci a pris une semaine supplémentaire qui n'était pas dans la portée initiale.
4. N'oubliez pas les formulaires
Gravity Forms gérait 14 types de formulaires différents sur le site WordPress. Nous les avons remplacés par React Hook Form + validation Zod sur le frontend et des server actions sur le backend, avec des soumissions allant vers leur CRM HubSpot existant. Cette migration seule a pris une semaine complète.
Chronologie et structure de l'équipe
Durée totale du projet : 10 semaines
| Semaine | Focus | Équipe |
|---|---|---|
| 1 | Architecture, conception de schéma Sanity, audit de contenu | 2 devs, 1 architect |
| 2-3 | Pipeline de sync de contenu, customisation Studio Sanity | 2 devs, 1 stratégiste contenu |
| 4-5 | Construction site marketing (Next.js) | 3 devs |
| 6-7 | Migration portail, authentification, formulaires | 3 devs |
| 8 | Centre documentation, audit SEO, carte redirections | 2 devs, 1 spécialiste SEO |
| 9 | QA, régression visuelle, test performance | 2 devs, 1 QA |
| 10 | Basculement progressif du trafic, surveillance, désaffectation WordPress | 2 devs, 1 DevOps |
La taille maximale de l'équipe était 4 personnes. La plupart du projet s'est déroulée avec 2-3 développeurs. Ce n'est pas un engagement de 15 personnes et 6 mois — c'est une équipe axée et expérimentée exécutant une migration bien planifiée.
Si vous envisagez une migration similaire pour votre organisation, nous avons documenté notre approche de développement CMS headless et notre structure de tarification est transparente. Nous sommes aussi heureux de sauter sur un appel pour discuter de votre situation spécifique — contactez-nous ici.
FAQ
Combien de temps dure généralement une migration WordPress vers Next.js ?
Pour un site de cette complexité (12 000 pages, portail client, centre de documentation), 10 semaines est réaliste avec une équipe expérimentée. Des sites marketing plus simples avec 100-500 pages peuvent être migrés en 4-6 semaines. La plus grande variable est la complexité du contenu — combien de types de posts personnalisés, types de blocs et fonctionnalités dépendantes de plugins vous exécutez.
Pouvez-vous migrer WordPress vers Next.js sans aucun temps d'arrêt ?
Oui, mais cela nécessite de la planification. La clé est d'exécuter les deux systèmes en parallèle avec un pipeline de synchronisation de contenu, puis d'utiliser le basculement de trafic au niveau DNS pour déplacer progressivement les utilisateurs vers le nouveau site. Nous l'avons fait avec succès pour plusieurs clients. L'exigence critique est que votre contenu reste synchronisé dans les deux systèmes pendant la période de transition.
Combien coûte une migration WordPress vers CMS headless ?
Cela dépend beaucoup de la portée. Une migration simple de site marketing pourrait coûter 30 K$-60 K$. Une migration enterprise comme celle de FinEdge — avec un portail client, exigences de conformité et 12 000 pages — était 185 K$. Le calcul du ROI importe plus que le coût absolu. L'investissement de FinEdge s'est amorti en moins de 5 mois grâce aux économies de licences seules.
Next.js est-il vraiment plus rapide que WordPress ?
Dans pratiquement tous les cas, oui — significativement plus rapide. WordPress génère HTML à chaque demande (à moins d'être fortement en cache), et même avec des plugins de caching comme WP Rocket, vous êtes limité par le temps de réponse de PHP et le poids de l'écosystème WordPress. Next.js avec ISR ou génération statique sert des pages pré-construites à partir de la périphérie. Nous voyons généralement des améliorations 3-5x dans les Core Web Vitals.
Quel CMS headless devrais-je utiliser avec Next.js ?
Cela dépend de votre équipe et de vos exigences. Sanity excelle dans la modélisation de contenu personnalisée et la collaboration en temps réel. Contentful est solide pour les équipes enterprise qui veulent une approche plus structurée et opinionnée, mais devient cher par siège. Storyblok est excellent si l'édition visuelle est une priorité. Pour les sites plus simples, même les fichiers Markdown dans un Git repo peuvent fonctionner. Nous évaluons cela sur une base projet par projet — il n'y a pas de réponse universelle.
Perdez-vous le SEO en migrant de WordPress vers Next.js ?
Non, si vous le faites correctement. Les trois choses qui importent : mappage exhaustif de redirections 301 pour qu'aucune URL existante ne renvoie 404, préservation de toutes les balises meta et données structurées, et soumission de sitemaps mis à jour à Google Search Console immédiatement après le basculement. FinEdge a vu une augmentation de 31% du trafic organique en 90 jours, largement entraînée par les améliorations Core Web Vitals.
Que se passe-t-il avec les plugins WordPress après la migration ?
La fonctionnalité de chaque plugin doit être répliquée ou remplacée. Certains sont simples — les plugins SEO sont remplacés par des métadonnées dans vos composants Next.js, les plugins de caching deviennent inutiles, et les plugins de formulaire sont remplacés par des bibliothèques de formulaire React. D'autres, comme les plugins de journalisation de conformité personnalisés, nécessitent du code de remplacement sur mesure. C'est pourquoi un audit approfondie des plugins pendant la découverte est essentiel.
Les éditeurs de contenu peuvent-ils toujours utiliser un éditeur visuel après passage à headless ?
Oui. Sanity Studio fournit une interface d'édition personnalisable avec aperçu en temps réel. C'est différent de l'éditeur de blocs de WordPress, mais la plupart des équipes de contenu le préfèrent après la courbe d'apprentissage initiale. L'outil Presentation de Sanity offre maintenant une véritable édition visuelle avec fonctionnalité click-to-edit sur l'aperçu en direct. Nous avons aussi mis en place des déploiements d'aperçu sur Vercel pour que les éditeurs voient exactement comment leur contenu apparaîtra avant publication.