Wanneer je Strapi bent ontgroeid: Bouwen met Payload + Supabase

Ik heb Strapi voor minstens een dozijn klantprojecten in de afgelopen jaren ingericht. Het is een geweldige CMS om mee te beginnen -- vriendelijk admin panel, fatsoenlijk plugin-ecosysteem, solide documentatie. Maar ergens rond de 18-maands grens raakt bijna elk team waar ik mee heb gewerkt tegen een muur. De migraties worden pijnlijk, de aanpassingen voelen hacky, en je TypeScript-liefhebbende frontend developers beginnen te mopperen over de developer experience. Als dat bekend klinkt, ben je niet alleen. Laat me je door de signalen lopen dat je uit Strapi bent gegroeid, en belangrijker nog, wat je in plaats daarvan moet bouwen.

When You've Outgrown Strapi CMS: Building with Payload + Supabase

Inhoudsopgave

De Honeymoon Phase: Waarom Strapi in het begin goed werkt

Laten we erkenning geven waar het toekomt. Strapi heeft 65K+ GitHub sterren om een reden. Wanneer je een nieuw content-gedreven project opstart, is de Content-Type Builder werkelijk nuttig. Je klikt rond in een GUI, definieert wat velden, en boom -- je hebt REST en GraphQL APIs. Niet-technische content editors kunnen zich aanmelden in het admin panel en binnen een uur beginnen publiceren.

Voor early-stage startups, marketing sites en blogs is Strapi een volkomen redelijke keuze. Het ondersteunt PostgreSQL, MySQL, MariaDB en SQLite. De plugin marketplace heeft meer dan 100 community extensions. En de community edition is gratis onder MIT licentie.

Ik heb Strapi genoeg keer aanbevolen. Ik ben hier niet om het af te kraken. Ik ben hier om te praten over wat daarna gebeurt.

Zes tekenen dat je Strapi bent ontgroeid

Dit zijn de patronen die ik herhaaldelijk zie. Als drie of meer van deze herkenbaar zijn, is het tijd om met je migratie te beginnen plannen.

1. Migraties maken je nerveus

De v4 naar v5 upgrade is degene die veel teams brak. Strapi documenteerde 50+ breaking changes. In de praktijk heb ik gezien dat migraties 40+ uur developer time kosten voor projecten met middelmatige complexiteit. Dat is geen minor version bump -- dat is een herschrijving van je content layer.

Als je tegen de volgende major version opziet omdat je weet dat het de helft van je custom controllers breekt, ben je uit het gereedschap gegroeid.

2. Je developers kampen tegen het framework

Strapiís Content-Type Builder is geweldig voor niet-technische gebruikers. Voor developers die in TypeScript leven en code-first schemas willen, is het een bottleneck. De GUI genereert bestanden die je niet mag bewerken. De lifecycle hooks voelen eraan vastgeplakt. TypeScript ondersteuning werd laat in v4 toegevoegd en is nog steeds niet native -- het is meer een nagedachte.

Wanneer je team workarounds voor het framework begint te bouwen in plaats van features ermee te bouwen, is dat een duidelijk signaal.

3. Performance wordt een probleem

Strapiís cold starts liggen doorgaans tussen de 500ms en 2000ms. Globale latentie zit tussen 200-500ms zonder agressieve caching. Voor een blog is dat prima. Voor een e-commerce platform dat gebruikers over meerdere regio's bedient, niet.

Ik had een klant die een multi-language productcatalogus op Strapi runde. Toen ze de ~50.000 content entries overschreden met diepe relaties, kropen API response times voorbij de 2-seconde grens. Geen enkele indexering hielp eraan.

4. Je hebt functies nodig die achter betaalde tiers vergrendeld zijn

Strapiís Growth plan loopt $45/maand en bevat 3 seats (extra seats op $15/seat). Dat ontgrendelt AI functies, live preview en content history. Enterprise pricing is custom.

Het probleem is niet de prijs -- het is de principe. Functies zoals live preview en content versioning voelen tabel-stakes voor een CMS in 2025. Ze achter een abonnement op een open-source tool vergrendelen wrijft developer teams verkeerd.

5. Je Stack is voorbij Strapiís Architectuur gegroeid

Als je volledig op Next.js, Vercel en TypeScript bent gegaan, voelt Strapi als een onhandig aanhangsel. Het draait als een aparte Node.js service. Dat betekent aparte deployments, aparte monitoring, aparte scaling concerns. Je frontend team deployt naar Vercel in seconden terwijl je CMS zijn eigen infrastructuur nodig heeft.

6. Custom extensions voelen als chirurgie

Wil je conditional field logic toevoegen? Geneste repeatable blocks met validatie? Custom admin panel componenten? In Strapi is elk van deze mogelijk maar pijnlijk. Het admin panel is een React app, maar uitbreiding ervan betekent navigeren door een propriëtair extension system dat niet voelt als normale React development.

When You've Outgrown Strapi CMS: Building with Payload + Supabase - architecture

Je opties begrijpen: Payload vs Supabase vs Blijven waar je bent

Voordat we verder gaan, moeten we duidelijk zijn over wat deze tools werkelijk zijn, want ik zie ze voortdurend door elkaar halen.

Tool Wat het werkelijk is Beste voor Niet geweldig voor
Strapi Open-source headless CMS met admin GUI Content editors, snelle API generation Code-first teams, high-perf apps
Payload CMS Code-first CMS framework dat in Next.js draait TypeScript devs, custom content apps Niet-technische solo operators
Supabase Open-source backend platform (DB, auth, storage, realtime) Application data, auth, file storage Content editing workflows
Directus SQL-first headless CMS met auto-generated APIs Teams met bestaande databases Diepe Next.js integratie
Sanity Managed headless CMS met real-time samenwerking Editorial teams, structured content Budget-bewuste self-hosters

Payload en Supabase zijn geen concurrenten -- ze vullen elkaar aan. Payload handelt je content modeling, admin UI en content APIs. Supabase handelt je database hosting, authenticatie, file storage en real-time subscriptions. Samen vervangen ze Strapi en nog meer.

Waarom Payload CMS de natuurlijke volgende stap is

Payload maakt serieuze golven in 2025 en in 2026. MG Software noemde het een "market disruptor" voor TypeScript/Next.js integratie, en ik denk dat dat nauwkeurig is.

Het fundamentele architectuurverschil is dit: Payload draait in je Next.js applicatie. Niet ernaast. Niet als aparte service. Erin. Je CMS en je frontend delen dezelfde deployment, dezelfde TypeScript types, dezelfde build process.

Code-First Schema Definitie

In plaats van door een GUI te klikken om content types te maken, schrijf je TypeScript:

import { CollectionConfig } from 'payload';

export const Products: CollectionConfig = {
  slug: 'products',
  admin: {
    useAsTitle: 'name',
    defaultColumns: ['name', 'price', 'status'],
  },
  access: {
    read: () => true,
    create: ({ req: { user } }) => user?.role === 'admin',
  },
  fields: [
    {
      name: 'name',
      type: 'text',
      required: true,
    },
    {
      name: 'price',
      type: 'number',
      min: 0,
    },
    {
      name: 'description',
      type: 'richText',
    },
    {
      name: 'category',
      type: 'relationship',
      relationTo: 'categories',
      hasMany: false,
    },
    {
      name: 'variants',
      type: 'array',
      fields: [
        { name: 'sku', type: 'text', required: true },
        { name: 'color', type: 'select', options: ['red', 'blue', 'green'] },
        {
          name: 'stock',
          type: 'number',
          admin: {
            condition: (data, siblingData) => siblingData?.sku !== undefined,
          },
        },
      ],
    },
  ],
  hooks: {
    afterChange: [
      async ({ doc, operation }) => {
        if (operation === 'update' && doc.stock === 0) {
          // Trigger restock notification
        }
      },
    ],
  },
};

Dat is een echte content type met conditional field logic, geneste arrays, relationship velden, role-based access control en lifecycle hooks. Alles in één bestand. Alles type-safe. Alles version-controlled in Git.

Probeer dat in Strapi zonder drie verschillende bestanden en het admin extension system aan te raken.

Drie API Layers

Payload genereert automatisch REST en GraphQL APIs van je schema. Maar de killer feature is de Local API -- directe database queries van je server-side code met nul HTTP overhead:

// Binnen een Next.js Server Component
import { getPayload } from 'payload';
import config from '@payload-config';

export default async function ProductPage({ params }) {
  const payload = await getPayload({ config });
  
  const product = await payload.findByID({
    collection: 'products',
    id: params.id,
    depth: 2, // Populate relationships 2 levels deep
  });
  
  return <ProductDetail product={product} />;
}

Geen fetch calls. Geen API routes. Geen serialization overhead. Dit is waarom Payload ongeveer 7x sneller benchmarks dan Strapi voor content retrieval in vergelijkbare setups.

Waar Supabase past (en waar niet)

Supabase is geen CMS. Ik wil echt duidelijk zijn over dat. Het is een backend platform gebouwd op PostgreSQL. Maar het lost verschillende problemen op die Strapi slecht handelt en Payload helemaal niet.

Wat Supabase naar de Stack brengt

  • Managed PostgreSQL: Payloadís PostgreSQL adapter maakt direct verbinding met een Supabase database. Je krijgt connection pooling, automatische backups en een dashboard voor directe SQL queries. Het Pro plan begint op $25/maand en schaalt met gebruik.
  • Authenticatie: Supabase Auth ondersteunt email/password, magic links, OAuth providers en row-level security. Als je app user-facing functies heeft buiten de CMS admin, is dit enorm.
  • File Storage: S3-compatible object storage met CDN. Payload kan media uploads handelen, maar Supabase Storage handelt application bestanden, user uploads en alles buiten de CMS context.
  • Real-time Subscriptions: PostgreSQLís LISTEN/NOTIFY gewrapt in een schone WebSocket API. Koppel dit met Payloadís live preview voor real-time content editing experiences.
  • Edge Functions: Deno-based serverless functions voor webhook handlers, background jobs en integraties.

Wat Supabase niet doet

Het geeft je geen admin panel voor content editors. Het genereert geen content APIs met rich-text velden en media management. Het handelt geen content localization of version history. Dat is Payloadís job.

De Payload + Supabase Stack: Architectuur Diepgang

Hier is hoe ik dit instellen voor teams die van Strapi af migreren. Dit is de architectuur die we doorgaans aanbevelen.

Project Structuur

├── src/
│   ├── app/                    # Next.js App Router
│   │   ├── (frontend)/         # Public-facing pages
│   │   └── (payload)/          # CMS admin routes (auto-generated)
│   ├── collections/            # Payload collection configs
│   │   ├── Posts.ts
│   │   ├── Products.ts
│   │   └── Users.ts
│   ├── globals/                # Payload global configs
│   │   └── SiteSettings.ts
│   ├── lib/
│   │   └── supabase.ts         # Supabase client initialization
│   └── payload.config.ts       # Main Payload config
├── supabase/
│   └── migrations/             # Supabase DB migrations
├── .env.local
└── package.json

Payload verbinden met Supabase PostgreSQL

// payload.config.ts
import { buildConfig } from 'payload';
import { postgresAdapter } from '@payloadcms/db-postgres';
import { lexicalEditor } from '@payloadcms/richtext-lexical';
import { Posts } from './collections/Posts';
import { Products } from './collections/Products';

export default buildConfig({
  db: postgresAdapter({
    pool: {
      connectionString: process.env.SUPABASE_DB_URL,
      // Use Supabase's connection pooler for serverless
      max: 10,
    },
  }),
  editor: lexicalEditor(),
  collections: [Posts, Products],
  secret: process.env.PAYLOAD_SECRET,
  typescript: {
    outputFile: path.resolve(__dirname, 'payload-types.ts'),
  },
});

Een belangrijk opmerking: gebruik Supabaseís connection pooler URL (poort 6543), niet de directe connection URL, wanneer je naar serverless omgevingen zoals Vercel deployt. Directe verbindingen werken prima voor lokale development.

Supabase Auth toevoegen voor Application Users

Payload handelt CMS admin authenticatie. Supabase handelt alles ander:

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);

// In een Server Component of API route
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';

export async function getServerSupabase() {
  const cookieStore = await cookies();
  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value, options }) =>
            cookieStore.set(name, value, options)
          );
        },
      },
    }
  );
}

Deze scheiding is schoon: Payload bezit content. Supabase bezit application data en user identity. Ze delen dezelfde PostgreSQL instance maar blijven in hun respectieve kaders.

Migratiestrategie: Weg van Strapi zonder je verstand te verliezen

Ik ga het niet verzachten -- migratie kost werk. Maar het is dramatisch minder pijnlijk dan een Strapi v4-naar-v5 upgrade, omdat je naar een systeem beweegt dat je bestaande mentale modellen respecteert.

Stap-voor-stap benadering

  1. Controleer je Strapi content types. Exporteer ze als JSON van de Content-Type Builder. Map elk naar een Payload collection config.
  2. Stel Payload in in een nieuw Next.js project. Voer npx create-payload-app@latest uit en selecteer de PostgreSQL adapter.
  3. Wijs Payload naar je Supabase database. Maak een nieuw Supabase project aan, pak de connection string, configureer de adapter.
  4. Recreëer schemas in TypeScript. Dit is de bulk van het werk. Elk Strapi content type wordt een Payload collection. Velden mappen bijna 1-op-1 -- text, number, richtext, relation, media.
  5. Exporteer data uit Strapi. Gebruik pg_dump als je op PostgreSQL was, of schrijf een script tegen de Strapi REST API om alle content te trekken.
  6. Importeer in Payload. Gebruik Payloadís Local API in een seed script om bulk content te maken.
  7. Update je frontend. Wissel Strapi API calls in voor Payload Local API calls (in Server Components) of REST/GraphQL calls (in client components).
  8. Deployer. Omdat Payload in Next.js draait, deployer je één applicatie in plaats van twee.

Voor complexe migraties kan ons team helpen de transitie te plannen. We hebben dit vaak genoeg gedaan om te weten waar de landmijnen zitten.

Performance Benchmarks en Real-World getallen

Hier zijn de getallen die ertoe doen, verzameld van gepubliceerde benchmarks en onze eigen testen in 2025:

Metriek Strapi v5 Payload 3.x Payload + Supabase
Cold start time 500-2000ms 100-300ms 150-350ms
Simple query (single item) 45-80ms 8-15ms 10-20ms
Complex query (populated, 3 levels) 200-500ms 30-80ms 40-100ms
Admin panel load 2-4s 1-2s 1-2s
Build time (500 pages, ISR) N/A (separate) 45-90s 50-100s
Global latency (no CDN) 200-500ms 50-150ms 60-160ms

De Supabase connection pooler voegt een kleine overhead toe vergeleken met een directe PostgreSQL verbinding, doorgaans 5-15ms. Dat is verwaarloosbaar in de praktijk.

Één voorbehoud: Payloadís populated field queries (diepe relationship resolution) zijn gemarkeerd als langzamer dan raw database queries -- ongeveer 15x langzamer dan directe Mongoose/Drizzle calls volgens GitHub issue #11325. Voor read-heavy pagina's aanbevelen ik Payloadís ISR of caching van populated resultaten in plaats van de database op elk verzoek te raken.

Wanneer deze stack niet de juiste keuze is

Ik zou je slecht uit doen als ik niet de scenario's noemde waar Payload + Supabase overkill of gewoon verkeerd is.

  • Je team schrijft geen TypeScript. Payload is code-first. Als je content team alles beheert en je hebt geen developers die de CMS onderhouden, is Strapiís GUI werkelijk beter. Of kijk naar Sanity of Contentful.
  • Je hebt vandaag een massief plugin ecosysteem nodig. Payloadís ecosysteem groeit maar het is kleiner dan Strapiís 100+ extensions. Als je een specifieke integratie nodig hebt die bestaat als Strapi plugin maar niet voor Payload, factor dan de build time in.
  • Je bouwt een simpele blog of marketing site. Strapi werkt prima hiervoor. Zo ook veel andere oplossingen. Over-engineeer het niet.
  • Je hebt edge-first performance nodig. Als sub-50ms globale latentie een harde vereiste is, kijk naar oplossingen op Cloudflare Workers. Payload draait op Node.js -- het is snel, maar het is niet edge-native.

Wil je praten of deze migratie zinvol is voor je specifieke project? Neem contact met ons op -- we geven je een eerlijk assessment, geen sales pitch.

Veelgestelde vragen

Is Payload CMS echt gratis? Ja. Payload is MIT-gelicentieerd en gratis om zelf te hosten zonder functie beperkingen. Er is een optionele Payload Cloud hosting service voor teams die geen infrastructuur willen beheren, maar alle CMS functies -- live preview, access control, localization, versioning -- zijn beschikbaar in de open-source versie. Vergelijk dat met Strapi, dat live preview en content history achter het $45/maand Growth plan vergrendelt.

Kan ik Supabase als CMS zelf gebruiken? Technisch gezien zou je een content management interface bovenop Supabase kunnen bouwen met behulp van zijn auto-generated APIs en Row Level Security. Maar je zou herbouwen wat Payload je direct biedt: een admin panel, rich text editing, media management, content versioning en access control. Supabase is een backend platform, geen CMS. Gebruik het voor waar het goed in is -- database hosting, auth, storage -- en laat Payload de content layer handelen.

Hoe lang duurt het om van Strapi naar Payload te migreren? Voor een typisch project met 10-20 content types en enkele duizenden entries, verwacht 2-4 weken developer time. De schema recreatie is het grootste stuk -- Strapi content types vertalen naar Payload TypeScript configs. Data migratie is meestal een dag of twee met een goed script. Frontend updates hangen af van hoe strak je code gekoppeld is aan Strapiís API response format. Teams die een data-access layer of abstractie gebruikten zullen het makkelijker hebben.

Werkt Payload met databases anders dan PostgreSQL? Payload ondersteunt zowel MongoDB als PostgreSQL via officiële database adapters. Voor de Supabase stack beschreven in dit artikel zou je de PostgreSQL adapter gebruiken. Als je uit MongoDB background komt, is Payloadís MongoDB adapter eigenlijk rijper omdat MongoDB Payloadís originele database was. Beide zijn production-ready in 2025.

Wat hiervan Directus als alternatief voor Strapi? Directus is een solide optie, vooral als je een bestaande SQL database hebt die je door een CMS interface wilt blootstellen. Het genereert automatisch een admin panel en APIs van je database schema, wat slim is. Het belangrijkste nadeel tegenover Payload is het gebrek aan diepe Next.js integratie -- Directus draait als aparte service, vergelijkbaar met Strapi. Als je team niet op de Next.js/Vercel stack zit, verdient Directus serieuze overweging.

Kan ik Payload + Supabase op Vercel deployen? Absoluut -- dit is eigenlijk het ideale deployment target. Omdat Payload in je Next.js app draait, deployen naar Vercel is net zo eenvoudig als pushen naar je Git repo. Supabase draait als managed service, dus er is niets om die kant op te deployen. Je totale infrastructuur wordt: Vercel voor compute en CDN, Supabase voor database en auth. Twee services, één deployment pipeline.

Is het Payload admin panel aanpasbaar? Zeer. De admin UI is gebouwd met React en ondersteunt custom componenten, custom views en custom velden. Je kunt dashboard widgets toevoegen, custom navigation items maken en elk default UI element overschrijven. Sinds Payload 3.x gebruikt admin customization React Server Components, wat betekent dat je custom admin code server-side data kan fetchen zonder API calls. Het is een ander wereld dan Strapiís admin extension system, wat ejecteren en patchen vereist.

Wat kost deze stack om in productie te draaien? Voor een klein-tot-middelmatig project: Vercel Pro op $20/maand + Supabase Pro op $25/maand = $45/maand totaal. Dat geeft je serverless compute, een managed PostgreSQL database met 8GB opslag, 250MB file storage, 50.000 maandelijkse actieve auth users en automatische backups. Schaal van daaraf op als nodig. Vergelijk dat met zelf-hosting Strapi op een VPS ($20-50/maand) plus je eigen database beheren, of Strapi Cloud Growth plan op $45/maand met beperkte seats. De Payload + Supabase combo is kostencompetitief en dramatisch gemakkelijker om te bedrijven.