WordPress naar Next.js Migratie op Vercel: Een gids voor 2026

In de afgelopen drie jaar heb ik meer dan een dozijn WordPress-sites naar Next.js gemigreerd. Sommige verliepen soepel. Sommige deden me op een dinsdag om 2 uur 's nachts mijn carrièrekeuzes ter discussie stellen. Het verschil tussen deze twee uitkomsten kwam bijna altijd neer op planning — specifiek, begrijpen wat WordPress daadwerkelijk deed voor de site voordat je het eruit trok.

Deze gids is alles wat ik had willen hebben voordat mijn eerste migratie. We gaan het volledige traject door: evalueren of je überhaupt moet migreren, je headless CMS kiezen, content verplaatsen, templates herbouwen, SEO afhandelen zonder ranglijsten kwijt te raken, en implementeren op Vercel met een setup die niet bezwijkt onder verkeerspieken.

Laten we erin duiken.

WordPress to Next.js Migration on Vercel: A 2026 Guide

Inhoudsopgave

Waarom migreren van WordPress naar Next.js in 2026?

Laten we eerlijk zijn — WordPress bestuurt nog steeds ongeveer 40% van het web in 2026. Het gaat nergens heen. Maar de redenen om weg te gaan zijn aantrekkelijker geworden:

Prestatieplafond. Zelfs met agressieve caching-plugins (WP Rocket, W3 Total Cache) bereiken de meeste WordPress-sites een muur rond 70-80 op Lighthouse prestatiescores. Plugin-bloat, render-blocking PHP en databasequery's op elke paginaweergave creëren overhead die geen enkele optimalisatie volledig kan elimineren.

Veiligheidsoppervlakte. WordPress had 149 gedocumenteerde beveiligingsproblemen in 2025 over core en populaire plugins. Elke plugin is een aanvalsvector. Elke thema-update is een mogelijke break. Als je WooCommerce draait, verdubbelt de oppervlakte.

Ontwikkelaarbeleving. Als je team React kent, voelt programmeren in PHP-templates als schrijven met je niet-dominante hand. Next.js 15's App Router, Server Components en ingebouwde caching geven je een moderne development workflow die WordPress niet kan evenaren.

Kosten op schaal. Managed WordPress hosting (WP Engine, Kinsta) kost $30–$300/maand voor fatsoenlijke prestaties. Vercel's Pro-plan van $20/gebruiker/maand met edge-functies en automatische schaling kost meestal minder terwijl het beter presteert.

Dat gezegd, migreer niet alleen omdat het trending is. Als je site een eenvoudige blog is met 50 posts en je klant werkt er wekelijks via de WordPress-admin aan, kan een migratie meer problemen opleveren dan oplossen. De beste kandidaten voor migratie zijn:

  • Sites met 500+ pagina's die betere prestaties nodig hebben
  • Teams die component-gebaseerde development willen
  • Sites waar plugin-conflicten onderhoudsrampen veroorzaken
  • E-commerce-sites die prestatieligrens van WooCommerce bereiken
  • Marketing-sites die A/B-testing en personalisatie aan de edge nodig hebben

Pre-migratie-audit: Wat WordPress daadwerkelijk doet

Dit is waar de meeste migraties mislukken. Mensen denken dat ze een blog migreren, maar WordPress verwerkt daadwerkelijk contactformulieren, redirects, beeldoptimalisatie, zoeken, reacties, authenticatie, cron-jobs en nog vijftien andere dingen die in plugin-configuraties verborgen zitten.

Voordat je een enkele regel Next.js-code schrijft, documenteer alles:

Plugin-inventaris

Exporteer je pluginlijst en categoriseer elke plugin:

wp plugin list --status=active --format=csv > active-plugins.csv

Voor elke plugin, antwoord: Wat doet dit, en wat vervangt het in het Next.js-ecosysteem?

WordPress-plugin Functie Next.js-vervanging
Yoast SEO Meta-tags, sitemaps, schema next-seo + aangepaste sitemap.xml-route
WP Rocket Caching, minificatie Vercel Edge Cache + Next.js ingebouwd
Contact Form 7 Formulierverwerking React Hook Form + API-route of Formspree
Wordfence Veiligheid Niet nodig (geen admin-surface)
WPML Meertalig next-intl of ingebouwde i18n-routing
WooCommerce E-commerce Shopify Storefront API of Saleor
Advanced Custom Fields Aangepaste content-modellen Content-modellering van je headless CMS
Redirection URL-redirects next.config.js redirects of Vercel-config
WP Cron Geplande taken Vercel Cron Jobs of aparte service
Imagify Beeldoptimalisatie next/image met Vercel Image Optimization

Content-inventaris

Tel en categoriseer je content:

SELECT post_type, post_status, COUNT(*) 
FROM wp_posts 
GROUP BY post_type, post_status;

Vergeet niet: aangepaste post-types, taxonomie-termen, gebruikersprofielen, menustructuren, widget-configuraties en optiewaarden. Die "eenvoudige" WordPress-site heeft waarschijnlijk meer content-types dan je denkt.

URL-mapping

Exporteer elke URL. Echt, elke. Gebruik Screaming Frog of een eenvoudige sitemap-crawl:

curl -s https://yoursite.com/sitemap_index.xml | \
grep -oP '<loc>\K[^<]+' | \
xargs -I {} curl -s {} | \
grep -oP '<loc>\K[^<]+' > all-urls.txt

Dit bestand is goud. Je zult het gebruiken voor redirect-mapping, SEO-behoud en QA-tests na migratie.

WordPress to Next.js Migration on Vercel: A 2026 Guide - architecture

Je Headless CMS Backend kiezen

Je hebt ergens nodig om content op te slaan en te beheren. De drie meest gebruikte paden in 2026:

Optie 1: WordPress als Headless CMS

Ja, je kunt WordPress als backend houden en Next.js als frontend gebruiken. WPGraphQL (nu op v2.1) maakt dit verrassend haalbaar. Je redacteuren behouden de bekende admin-interface. Je krijgt een modern frontend.

// lib/wordpress.js
const API_URL = process.env.WORDPRESS_GRAPHQL_URL;

export async function getPostBySlug(slug) {
  const res = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: `
        query PostBySlug($slug: ID!) {
          post(id: $slug, idType: SLUG) {
            title
            content
            date
            featuredImage {
              node {
                sourceUrl
                altText
              }
            }
            seo {
              title
              metaDesc
              opengraphImage {
                sourceUrl
              }
            }
          }
        }
      `,
      variables: { slug },
    }),
    next: { revalidate: 60 },
  });
  const json = await res.json();
  return json.data.post;
}

Het nadeel? Je onderhoudt nog steeds een WordPress-installatie. Beveiligingsupdates, PHP-versiebeheer, databaseback-ups — het blijft allemaal jouw verantwoordelijkheid. En je betaalt nog steeds voor WordPress-hosting.

Optie 2: Purpose-Built Headless CMS

Dit is wat ik voor de meeste migraties aanbeveel. Verplaats je content naar een CMS dat van nul af aan werd gebouwd voor API-first levering.

CMS Prijzen (2026) Het beste voor Content-modellering API-type
Sanity Gratis tier, €15/gebruiker/mnd Pro Complexe content, real-time samenwerking Uitstekend, code-gedefinieerd GROQ + GraphQL
Contentful Gratis tier, €300/mnd Team Enterprise, grote teams Goed, UI-gedefinieerd REST + GraphQL
Storyblok Gratis tier, €106/mnd Business Visueel bewerken, componenten Geweldig, visueel REST + GraphQL
Strapi v5 Gratis (self-hosted), Cloud vanaf €29/mnd Volledige controle, open source Flexibel, UI-gedefinieerd REST + GraphQL
Payload CMS 3.0 Gratis (self-hosted) Developers die code-first willen Uitstekend, code-gedefinieerd REST + GraphQL

Als je team bij ons de migratie afhandelt, bevelen we meestal Sanity of Payload aan voor headless CMS-development — ze geven developers de meeste controle over content-modellering terwijl redacteuren blij blijven.

Optie 3: Markdown/MDX in de repository

Voor developerblog's en documentatiesites is het opslaan van content als MDX-bestanden in je Git-repo het eenvoudigste. Geen CMS om te beheren, geen API-oproepen, content versiebeheerd naast code. Maar dit werkt alleen als je content-redacteuren comfortabel zijn met Git-workflows.

Content migratiestategie

Exporteren uit WordPress

De ingebouwde WordPress-export (Tools → Export) geeft je een XML-bestand. Het is een begin, maar het is rommelig. Voor gestructureerde migratie gebruik ik een aangepast WP-CLI-script:

// export-content.php
<?php
$posts = get_posts([
    'post_type' => ['post', 'page', 'your_custom_type'],
    'posts_per_page' => -1,
    'post_status' => 'publish',
]);

$export = [];
foreach ($posts as $post) {
    $export[] = [
        'id' => $post->ID,
        'title' => $post->post_title,
        'slug' => $post->post_name,
        'content' => apply_filters('the_content', $post->post_content),
        'excerpt' => $post->post_excerpt,
        'date' => $post->post_date,
        'modified' => $post->post_modified,
        'author' => get_the_author_meta('display_name', $post->post_author),
        'categories' => wp_get_post_categories($post->ID, ['fields' => 'names']),
        'tags' => wp_get_post_tags($post->ID, ['fields' => 'names']),
        'featured_image' => get_the_post_thumbnail_url($post->ID, 'full'),
        'acf' => function_exists('get_fields') ? get_fields($post->ID) : [],
        'yoast' => [
            'title' => get_post_meta($post->ID, '_yoast_wpseo_title', true),
            'description' => get_post_meta($post->ID, '_yoast_wpseo_metadesc', true),
        ],
    ];
}

file_put_contents('export.json', json_encode($export, JSON_PRETTY_PRINT));

Content transformeren

WordPress-content wordt opgeslagen als HTML met Gutenberg-blokmarkering. Je moet bepalen: behoud de HTML en render het, of converteer naar de gestructureerde indeling van je CMS?

Voor Sanity gebruik ik @sanity/block-tools om HTML in Portable Text om te zetten. Voor Contentful verwerkt hun migratie-CLI rich text-conversie. In beide gevallen, plan tijd in voor content-opschoning — WordPress-content zit vol met [shortcodes], inline-stijlen en kapotte HTML die moet worden opgeschoond.

// migrate-to-sanity.js
import { htmlToBlocks } from '@sanity/block-tools';
import { JSDOM } from 'jsdom';
import { Schema } from '@sanity/schema';

const schema = Schema.compile({ /* your schema */ });
const blockContentType = schema.get('post')
  .fields.find(f => f.name === 'body').type;

function convertPost(wpPost) {
  return {
    _type: 'post',
    title: wpPost.title,
    slug: { current: wpPost.slug },
    publishedAt: wpPost.date,
    body: htmlToBlocks(
      wpPost.content,
      blockContentType,
      { parseHtml: (html) => new JSDOM(html).window.document }
    ),
  };
}

Beeldmigratie

Sla dit niet over. Download elk beeld van wp-content/uploads, upload opnieuw naar je CMS of CDN (Cloudinary, Vercel Blob Storage, S3) en werk alle content-verwijzingen bij. Ik schrijf meestal een script dat:

  1. De export-JSON doorzoekt op afbeeldings-URL's
  2. Elk beeld downloadt
  3. Naar de nieuwe opslag uploadt
  4. Een URL-mapping-bestand maakt
  5. Find-and-replace uitvoert over alle content

Je frontend herbouwen in Next.js 15

Next.js 15 (stabiel sinds eind 2024, met 15.2 actueel in 2026) gebruikt standaard de App Router. Hier is de structuur die ik voor content-zware sites gebruik:

app/
├── layout.tsx          # Root-layout met fonts, analytics
├── page.tsx            # Homepage
├── blog/
│   ├── page.tsx        # Blog-listing met paginering
│   └── [slug]/
│       └── page.tsx    # Individuele blogposts
├── [slug]/
│   └── page.tsx        # Generieke pagina's
├── sitemap.ts          # Dynamische sitemap-generatie
├── robots.ts           # robots.txt
└── not-found.tsx       # Aangepaste 404

Statische generatie met ISR

Voor de meeste content-pagina's is Incremental Static Regeneration het zoete middel — statische prestaties met dynamische versheid:

// app/blog/[slug]/page.tsx
import { getPostBySlug, getAllPostSlugs } from '@/lib/cms';
import { notFound } from 'next/navigation';

export async function generateStaticParams() {
  const slugs = await getAllPostSlugs();
  return slugs.map((slug) => ({ slug }));
}

export async function generateMetadata({ params }) {
  const post = await getPostBySlug(params.slug);
  if (!post) return {};
  return {
    title: post.seo?.title || post.title,
    description: post.seo?.description || post.excerpt,
    openGraph: {
      images: [post.featuredImage?.url],
    },
  };
}

export const revalidate = 3600; // Elke uur opnieuw valideren

export default async function BlogPost({ params }) {
  const post = await getPostBySlug(params.slug);
  if (!post) notFound();

  return (
    <article className="prose lg:prose-xl">
      <h1>{post.title}</h1>
      <time dateTime={post.date}>{formatDate(post.date)}</time>
      <PostBody content={post.body} />
    </article>
  );
}

Voor sites die real-time updates nodig hebben (nieuws, live content), gebruik on-demand revalidatie via webhooks van je CMS. De meeste headless CMS-platforms ondersteunen webhook-triggers bij content-publicatie.

Als je kijkt naar Next.js development en meer wilt begrijpen over de rendering-afwegingen, hebben we daar aparte informatie over geschreven.

URL-structuur en SEO-behoud

Dit is niet onderhandelbaar. Als je je URL-structuur kwijtraakt, verlies je je zoekmachineranglijsten. Klaar.

Redirect-map

WordPress gebruikt URL-patronen zoals /2024/03/post-slug/ of /category/term/. Je Next.js-site gebruikt waarschijnlijk /blog/post-slug. Maak een redirect-map:

// next.config.js
module.exports = {
  async redirects() {
    return [
      // Op datum gebaseerde URL's naar schone slugs
      {
        source: '/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/blog/:slug',
        permanent: true,
      },
      // Categorieën-archieven
      {
        source: '/category/:slug',
        destination: '/blog?category=:slug',
        permanent: true,
      },
      // Paginering
      {
        source: '/page/:num',
        destination: '/blog?page=:num',
        permanent: true,
      },
      // Feed-URL's
      {
        source: '/feed',
        destination: '/rss.xml',
        permanent: true,
      },
    ];
  },
};

Voor grote sites (1000+ redirects), gebruik Vercel's vercel.json-configuratie of middleware in plaats van dit — next.config.js redirects hebben een zachte limiet van ongeveer 1024 ingangen voordat bouwlijnen beginnen te lijden.

Gestructureerde data

WordPress-plugins zoals Yoast genereren automatisch JSON-LD. Je moet dit repliceren:

// components/structured-data.tsx
export function ArticleSchema({ post }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: post.title,
    datePublished: post.date,
    dateModified: post.modified,
    author: {
      '@type': 'Person',
      name: post.author,
    },
    image: post.featuredImage?.url,
    publisher: {
      '@type': 'Organization',
      name: 'Your Site Name',
      logo: { '@type': 'ImageObject', url: '/logo.png' },
    },
  };

  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
    />
  );
}

XML-sitemap

Next.js 15 maakt dynamische sitemaps moeiteloos:

// app/sitemap.ts
import { getAllPosts, getAllPages } from '@/lib/cms';

export default async function sitemap() {
  const posts = await getAllPosts();
  const pages = await getAllPages();

  return [
    { url: 'https://yoursite.com', lastModified: new Date() },
    ...pages.map((page) => ({
      url: `https://yoursite.com/${page.slug}`,
      lastModified: page.modified,
    })),
    ...posts.map((post) => ({
      url: `https://yoursite.com/blog/${post.slug}`,
      lastModified: post.modified,
    })),
  ];
}

Implementeren op Vercel: Configuratie die echt werkt

Projectopstelling

npx create-next-app@latest my-migrated-site --typescript --tailwind --app
cd my-migrated-site
vercel link

Omgevingsvariabelen

Stel deze in op Vercel's dashboard, niet in .env-bestanden die naar Git zijn gecommit:

CMS_API_URL=https://your-cms-api-endpoint
CMS_API_TOKEN=your-read-only-token
REVALIDATION_SECRET=a-random-string-for-webhook-auth
SITE_URL=https://yoursite.com

Vercel-configuratie

// vercel.json
{
  "crons": [
    {
      "path": "/api/revalidate-sitemap",
      "schedule": "0 */6 * * *"
    }
  ],
  "headers": [
    {
      "source": "/fonts/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    }
  ]
}

On-Demand Revalidatie-webhook

// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidation-secret');
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
  }

  const body = await request.json();
  const { slug, type } = body;

  if (type === 'post') {
    revalidatePath(`/blog/${slug}`);
    revalidatePath('/blog'); // Hervalideer listing ook
  } else {
    revalidatePath(`/${slug}`);
  }

  return NextResponse.json({ revalidated: true });
}

Wijs je CMS-webhook naar https://yoursite.com/api/revalidate met de geheime header. Nu verschijnen content-updates binnen seconden zonder volledige herbouwen.

Prestatiebenchmarks: Voor en na

Dit zijn echte getallen van migraties die we in 2025-2026 hebben afgerond:

Metric WordPress (WP Engine) Next.js (Vercel) Verbetering
Lighthouse-prestatie 62-78 95-100 +30-40%
Largest Contentful Paint 2,8-4,2s 0,8-1,4s 60-70% sneller
Time to First Byte 800ms-1,5s 50-120ms 90%+ sneller
Cumulative Layout Shift 0,12-0,25 0,01-0,05 ~80% reductie
Maandelijks hostingkosten €115/mnd gem. €20-40/mnd 60-80% besparing
Bouwlijntijd (500 pagina's) N/A (dynamisch) 45-90 seconden N/A
Pagina's/seconde (ISR) 15-30 req/s 10.000+ vanaf edge Orden van grootte

De TTFB-verbetering alleen is al de moeite van de migratie waard. WordPress genereert elke pagina door PHP en MySQL. Vercel serveert voorgegenereerde pagina's vanaf edge-nodes op 300+ locaties wereldwijd.

Veelgebruikte migratievalkuilen

Valkuil 1: WordPress RSS-feeds vergeten. Als mensen zich op je feed abonneren, redirect /feed/ en /rss/ naar een nieuw RSS-eindpunt. Next.js genereert geen feeds standaard — je hebt een aangepaste route nodig.

Valkuil 2: WordPress-shortcodes missen. Content geëxporteerd uit WordPress zit vol met [gallery], [embed] en plugin-specifieke shortcodes. Als je deze niet parseert en converteert, worden ze als platte tekst weergegeven. Schrijf transformers voor elk shortcode-type dat je content gebruikt.

Valkuil 3: WordPress-commentaargegevens negeren. Als je waardevolle comment-threads hebt, migreer ze naar een service zoals Disqus of bouw een aangepast comment-systeem. De meeste mensen laten commentaren gewoon vallen, maar check eerst met betrokkenen.

Valkuil 4: Interne links niet testen. WordPress-content zit vol met interne links met absolute URL's (https://yoursite.com/old-path/). Deze moeten worden bijgewerkt naar relatieve paden of je nieuwe URL-structuur. Een eenvoudige regex find-and-replace tijdens migratie verwerkt de meeste gevallen.

Valkuil 5: wp-content/uploads-verwijzingen vergeten. Zelfs na het migreren van afbeeldingen, kan oude content /wp-content/uploads/2024/03/image.jpg-paden verwijzen. Stel een catch-all redirect in of proxy deze naar je nieuwe afbeeldings-CDN.

Als dit overweldigend voelt, dat is eerlijk gezegd normaal. Een juiste migratie duurt 4-12 weken afhankelijk van de sitecomplexiteit. Bekijk onze prijzen of neem rechtstreeks contact op als je ervaren handen op het project wilt.

Veelgestelde vragen

Hoe lang duurt een WordPress naar Next.js migratie? Voor een site met 100-500 pagina's, plan 4-8 weken in met een dedicated developer. Grotere sites met aangepaste post-types, e-commerce of meertalige content kunnen 8-16 weken duren. De content-migratie zelf is meestal 20% van het werk — de andere 80% is templates herbouwen, edge cases afhandelen en QA-testen van elke URL.

Verlies ik mijn Google-ranglijsten tijdens migratie? Niet als je redirects goed afhandelt. Implementeer 301-redirects voor elke URL die verandert, behoud je meta-titels en beschrijvingen, dien je nieuwe sitemap in bij Google Search Console en gebruik het adreswijzigingsinstrument als je domein verandert. Verwacht een kleine ranglijstfluctuatie gedurende 2-4 weken, vervolgens herstel of verbetering naarmate Google betere Core Web Vitals herkent.

Kan ik WordPress als mijn CMS blijven gebruiken met Next.js? Absoluut. Dit wordt "headless WordPress" genoemd en is een populaire benadering. Gebruik WPGraphQL om je content als API bloot te stellen, en consumeer het vervolgens van Next.js. Je redacteuren behouden de WordPress-admin die ze kennen. Het belangrijkste nadeel is dat je nog steeds een WordPress-installatie onderhoudt — beveiligingsupdates, hosting, de hele stack.

Hoeveel kost het om van WordPress naar Next.js te migreren? DIY met één developer: 100-300 uur werk. Agencymigratie: typisch $15.000–$75.000 afhankelijk van complexiteit. Doorlopende hostingkosten dalen meestal — Vercel Pro op $20/gebruiker/maand tegenover managed WordPress-hosting op $50–$300/maand. De ROI komt van lagere hostingkosten, betere prestaties (wat conversietarieven verbetert) en lager onderhoudsoverhead.

Moet ik Pages Router of App Router in Next.js 15 gebruiken? App Router, volledige. In 2026 is de App Router de stabiele standaard met Server Components, streaming en parallel routes. De Pages Router werkt nog steeds en is niet afgekeurd, maar nieuwe functies en optimalisaties zijn App Router-first. Elke migratie die we doen, gebruikt de App Router exclusief. Bekijk onze Next.js development-mogelijkheden voor meer over onze benadering.

Hoe zit het met formulieren en dynamische functionaliteit? Next.js API-routes (of Server Actions in de App Router) verwerken formulierinzendingen, zoeken, authenticatie en andere server-side logica. Voor contactformulieren kun je Server Actions gebruiken met een service zoals Resend voor e-mailbezorging. Voor zoeken, overweeg Algolia of Meilisearch. Voor authenticatie, NextAuth.js (nu Auth.js v5) dekt de meeste use-cases.

Is Vercel de enige optie voor het hosten van Next.js? Nee. Je kunt Next.js implementeren op Netlify, AWS Amplify, Cloudflare Pages of zelfhost met Node.js. Vercel is echter gemaakt door het Next.js-team, en de integratie toont dit — ISR, edge-middleware, beeldoptimalisatie en analytics werken allemaal het beste op Vercel. De DX-kloof tussen Vercel en alternatieven is in 2026 kleiner geworden, maar Vercel blijft het gemakkelijkste pad.

Wat als ik een WooCommerce-winkel moet migreren? Dit is een groter project. De meeste teams migreren de winkelpresentatie naar Next.js terwijl ze de commerce-backend verplaatsen naar Shopify (via Storefront API), Medusa.js of Saleor. Het Hydrogen-framework van Shopify is een ander optie, maar als je volledige controle over het frontend wilt, is Next.js met Shopify's API het meest bewezen pad. Plan in dat de e-commerce-migratie 4-8 weken aan je timeline toevoegt.