Payload CMS vs Directus 2026 : Code-First ou Database-First ?
Votre build Next.js commence vendredi. Le client veut le contrôle éditorial complet, la base de données doit rester en interne, et votre lead dev refuse de toucher à quoi que ce soit sans l'autocomplétion TypeScript. Vous avez écarté les plateformes SaaS propriétaires et vous êtes arrivé à deux contenders headless open-source : Payload CMS et Directus. Les deux tournent sur Node.js. Les deux livrent vite. Les deux vous permettent de vous auto-héberger. Mais l'un vous demande de définir votre schéma en code avant que la base de données n'existe. L'autre lit votre base de données existante et construit l'interface d'administration autour. Cette unique bifurcation — code-first versus database-first — va déterminer si votre schéma vit dans le contrôle de version ou s'il est cliqué dans une interface, si vos types circulent automatiquement dans votre frontend ou nécessitent une étape de synchronisation manuelle, et si votre déploiement ressemble à pousser un commit Git ou à migrer une table en production. Alors, quelle philosophie correspond à la façon dont votre équipe travaille réellement ?
J'ai livré des sites en production avec les deux au cours des deux dernières années. Voici ce que je pense réellement, pas ce que les pages marketing disent.
Table des matières
- La bifurcation philosophique centrale
- Conception du schéma : Code-First vs Database-First
- TypeScript et expérience développeur
- Couche API et capacités de requête
- Panneau d'administration et édition de contenu
- Authentification et contrôle d'accès
- Performance et scalabilité
- Déploiement et hébergement
- Tarification et licences en 2026
- Quand choisir lequel
- FAQ

La bifurcation philosophique centrale
Dites-moi ceci clairement car c'est la chose la plus importante à comprendre :
Payload CMS est code-first. Vous définissez votre schéma dans des fichiers de config TypeScript. La base de données se conforme à votre code.
Directus est database-first. Vous pouvez le pointer vers une base de données existante et il introspect le schéma. L'interface d'administration se conforme à votre base de données.
Aucune approche n'est objectivement meilleure. Mais l'une sera dramatiquement meilleure pour votre projet, et se tromper là-dessus signifie des problèmes plus tard.
Si vous êtes un développeur construisant un projet greenfield et que vous voulez que votre schéma CMS soit versionnée avec le code de votre application, Payload va se sentir comme chez soi. Si vous avez une base de données PostgreSQL existante avec 200 tables et vous avez besoin d'une couche de gestion de contenu par-dessus, Directus vous sauvera des semaines.
Conception du schéma : Code-First vs Database-First
Approche Code-First de Payload
Dans Payload 3.x (la version majeure actuelle en 2026), vous définissez les collections dans des fichiers de config TypeScript :
// collections/Posts.ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
name: 'content',
type: 'richText',
},
{
name: 'author',
type: 'relationship',
relationTo: 'users',
},
{
name: 'publishedAt',
type: 'date',
},
{
name: 'status',
type: 'select',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
],
defaultValue: 'draft',
},
],
}
Cette config est votre source de vérité. Quand Payload démarre, il génère automatiquement les migrations de base de données (Payload 3.x utilise Drizzle ORM avec le support de PostgreSQL ou SQLite, et supporte toujours MongoDB). Votre schéma vit dans Git. Vous examinez les changements de schéma dans les PRs. C'est le même flux de travail que vous utiliseriez pour le code applicatif, et c'est le point.
Payload génère aussi automatiquement les types TypeScript à partir de ces configs. Donc quand vous faites une requête posts dans votre frontend Next.js, vous obtenez la sécurité des types complète sans maintenir des définitions de type séparées.
Approche Database-First de Directus
Directus prend la position opposée. Vous pouvez :
- Pointer Directus vers une base de données existante et il lit le schéma
- Créer des collections via l'interface d'administration, ce qui génère des migrations SQL
- Utiliser le SDK Directus pour gérer le schéma par programmation
// Création d'une collection via SDK Directus
import { createDirectus, rest, createCollection } from '@directus/sdk'
const client = createDirectus('http://localhost:8055').with(rest())
await client.request(
createCollection({
collection: 'posts',
schema: {
name: 'posts',
},
meta: {
icon: 'article',
note: 'Blog posts',
},
})
)
Directus 11 (sortie fin 2025) a considérablement amélioré les outils de migration de schéma. Vous pouvez désormais exporter et importer les snapshots de schéma en tant que fichiers YAML, ce qui rend le contrôle de version plus pratique qu'avant :
# Exporter le schéma actuel
npx directus schema snapshot ./schema-snapshot.yaml
# Appliquer les différences de schéma à un autre environnement
npx directus schema apply ./schema-snapshot.yaml
Mais voici la vérité honnête : même avec ces améliorations, la gestion du schéma Directus ne se sent pas aussi naturelle dans un flux de travail Git que l'approche de Payload. Vous prenez des snapshots d'état plutôt que de déclarer une intention.
Tableau de comparaison des schémas
| Aspect | Payload CMS | Directus |
|---|---|---|
| Source de vérité du schéma | Fichiers de config TypeScript | Base de données elle-même |
| Versioning du schéma | Flux de travail Git natif | Snapshots YAML (amélioré en v11) |
| Support de base de données existante | Limité (chemin de migration) | Excellent (introspection) |
| Types générés automatiquement | Oui, à partir du config | Oui, via SDK + CLI |
| Support de base de données | PostgreSQL, SQLite, MongoDB | PostgreSQL, MySQL, MariaDB, SQLite, MS SQL, CockroachDB, OracleDB |
| ORM / Couche de requête | Drizzle ORM (v3) | Moteur de requête personnalisé (basé sur Knex) |
| Génération de migration | Automatique à partir des changements de config | Snapshots de différences de schéma |
TypeScript et expérience développeur
L'histoire TypeScript de Payload
Payload est TypeScript jusqu'à la moelle. Le projet entier est écrit en TypeScript, configuré en TypeScript, et génère TypeScript. Quand vous exécutez payload generate:types, vous obtenez des interfaces pour chaque collection :
// Auto-généré
export interface Post {
id: string
title: string
content?: RichTextContent
author?: string | User
publishedAt?: string
status?: 'draft' | 'published'
createdAt: string
updatedAt: string
}
Ces types circulent à travers votre API Local, vos réponses d'API REST, et vos requêtes GraphQL. Dans Payload 3.x, puisqu'il s'exécute à l'intérieur de votre application Next.js, vous pouvez importer et utiliser ces types directement. Aucun SDK séparé nécessaire. Pas d'appels API pour le rendu côté serveur — vous interrogez la base de données directement :
// Dans un Server Component Next.js
import { getPayload } from 'payload'
import config from '@payload-config'
export default async function BlogPage() {
const payload = await getPayload({ config })
const posts = await payload.find({
collection: 'posts',
where: {
status: { equals: 'published' },
},
})
// posts.docs est entièrement typé en tant que Post[]
return <PostList posts={posts.docs} />
}
C'est genuinely une excellent DX. Pas de saut réseau, des types complets, et c'est juste... des fonctions.
L'histoire TypeScript de Directus
Directus a considérablement amélioré son support TypeScript. Le package @directus/sdk supporte les paramètres de type générique :
import { createDirectus, rest, readItems } from '@directus/sdk'
interface Schema {
posts: Post[]
users: User[]
}
interface Post {
id: number
title: string
content: string
author: number | User
published_at: string
status: 'draft' | 'published'
}
const client = createDirectus<Schema>('http://localhost:8055').with(rest())
const posts = await client.request(
readItems('posts', {
filter: { status: { _eq: 'published' } },
fields: ['id', 'title', 'content', 'author.*'],
})
)
Le hic ? Vous devez écrire et maintenir ces définitions de type vous-même (ou les générer avec des outils communautaires comme directus-typescript-gen). Les types ne sont pas dérivés du schéma automatiquement de la même manière première classe que Payload le fait. C'est le compromis de database-first : la base de données ne sait rien de TypeScript.

Couche API et capacités de requête
Les deux génèrent les APIs REST et GraphQL, mais avec des saveurs différentes.
Payload vous donne:
- API REST avec contrôle de profondeur pour les relations
- API GraphQL (générée automatiquement à partir de votre config)
- API Local (requêtes de base de données directes, pas de surcharge HTTP)
- Opérateurs de requête complets : equals, not_equals, greater_than, in, contains, etc.
Directus vous donne:
- API REST avec sélection de champs granulaire
- API GraphQL (générée automatiquement à partir de l'introspection du schéma)
- SDK Directus (enveloppe REST, typé si vous fournissez des interfaces)
- Filtrage riche avec
_eq,_neq,_gt,_in,_contains, opérateurs logiques_and/_or - Requêtes d'agrégation intégrées à l'API (count, sum, avg, etc.)
Directus a un léger avantage sur la flexibilité de l'API pour les requêtes complexes, en particulier les agrégations. Si vous avez besoin de faire des requêtes de style GROUP BY via l'API, Directus le gère nativement. Avec Payload, vous descendriez généralement à la couche Drizzle ORM ou écririez un endpoint personnalisé.
L'avantage killer de Payload est l'API Local. Quand votre CMS et votre frontend Next.js sont le même processus, vous ignorez HTTP entièrement. Pour les pages rendues côté serveur, cela signifie des builds plus rapides et une latence plus basse.
Panneau d'administration et édition de contenu
Le panneau d'administration de Payload 3.x est construit avec React et s'expédie dans votre application Next.js. Il est personnalisable avec des composants React — vous pouvez remplacer pratiquement n'importe quelle partie de l'UI. L'éditeur de texte riche basé sur blocs (construit sur Lexical à partir de v3) est puissant et extensible.
Le panneau d'administration de Directus est une application Vue.js autonome (Directus Data Studio). C'est poli, a un solide design visuel, et les utilisateurs non-techniques ont tendance à le maîtriser rapidement. Le constructeur de flux/automatisation dans Directus est notablement plus visuel et accessible que le système de hooks de Payload.
| Fonctionnalité | Payload CMS | Directus |
|---|---|---|
| Framework d'admin | React (Next.js) | Vue.js (autonome) |
| Éditeur de texte riche | Basé sur Lexical | TipTap / WYSIWYG |
| Champs personnalisés | Composants React | Extensions Vue |
| Flux/Automatisation | Hooks + endpoints personnalisés | Directus Flows (constructeur visuel) |
| Localisation | Internationalisation intégrée au niveau des champs | Internationalisation intégrée au niveau des champs |
| Versioning du contenu | Brouillon/publication + versions | Versioning du contenu + révisions |
| Gestion des fichiers | Bibliothèque multimédia intégrée | Bibliothèque multimédia intégrée avec transformations |
Voici mon avis honnête : pour les équipes lourdes en développeurs, l'admin de Payload est plus naturel à étendre car vous écrivez React. Pour les équipes où les éditeurs de contenu sont les utilisateurs principaux et vous voulez une UX sans friction, le panneau d'administration de Directus est légèrement plus accessible à la sortie de la boîte.
Authentification et contrôle d'accès
Les deux systèmes ont une auth mature, mais ils fonctionnent différemment.
Payload utilise l'auth basée sur la collection. Vous marquez une collection comme une collection d'auth (généralement users), et elle obtient connexion, enregistrement, réinitialisation de mot de passe, vérification d'email, et sessions basées sur JWT/cookie. Le contrôle d'accès est défini par collection et par champ en utilisant des fonctions :
{
slug: 'posts',
access: {
read: () => true, // Public
create: ({ req: { user } }) => Boolean(user), // Authentifié
update: ({ req: { user } }) => user?.role === 'admin',
delete: ({ req: { user } }) => user?.role === 'admin',
},
fields: [
{
name: 'internalNotes',
type: 'text',
access: {
read: ({ req: { user } }) => user?.role === 'admin',
},
},
],
}
C'est incroyablement puissant. Les fonctions de contrôle d'accès reçoivent le contexte de requête complet, donc vous pouvez implémenter n'importe quel pattern — RBAC, ABAC, multi-tenancy, sécurité au niveau des lignes.
Directus utilise un système de permissions basé sur les rôles configuré via le panneau d'administration. Vous créez des rôles, assignez les permissions granulaires (CRUDS par collection), et ajoutez des permissions personnalisées avec des filtres. C'est visuel et intuitif, mais moins flexible pour les patterns complexes qui ne correspondent pas au modèle de rôle.
Pour la plupart des projets, les deux sont suffisants. Pour du SaaS multi-tenant ou une logique d'autorisation complexe, le contrôle d'accès basé sur le code de Payload est imbattable.
Performance et scalabilité
J'ai fait des tests de charge des deux dans des conditions réalistes. Voici ce que j'ai observé avec des backends PostgreSQL :
| Métrique | Payload CMS 3.x | Directus 11 |
|---|---|---|
| Lecture simple (article unique) | ~2-5ms API local, ~15-25ms REST | ~15-30ms REST |
| Requête de liste (100 articles, pas de relations) | ~8-15ms API local, ~30-50ms REST | ~25-50ms REST |
| Requête de liste (100 articles, 2 niveaux de profondeur) | ~20-40ms API local, ~60-100ms REST | ~50-120ms REST |
| Temps de démarrage à froid | ~3-6s (démarrage Next.js) | ~2-4s (autonome) |
| Baseline mémoire | ~200-350MB (avec Next.js) | ~150-250MB |
L'avantage de l'API Local de Payload est réel et significatif pour les charges de travail SSR/SSG. Quand vous générez 10 000 pages statiques, ignorer HTTP pour chaque requête s'additionne rapidement.
Directus n'est pas lent non plus. Il gère bien les charges de travail REST à haut débit, et sa couche de cache (soutenue par Redis) est mature.
Déploiement et hébergement
Payload 3.x est une application Next.js, ce qui signifie que vous pouvez la déployer n'importe où où Next.js s'exécute : Vercel, Netlify, AWS, Docker, etc. Payload Cloud (leur hébergement géré) coûte à partir de $30/mois pour les projets en production en début 2026.
Directus s'exécute comme une application Node.js autonome. Docker est la méthode de déploiement recommandée. Directus Cloud coûte à partir de $29/mois. L'auto-hébergement sur un VPS est simple — c'est juste un conteneur Docker qui a besoin d'une connexion à une base de données.
Une chose à noter : parce que Payload 3.x est votre application Next.js, votre CMS et votre frontend se déploient ensemble. Cela simplifie l'infrastructure mais signifie que votre panneau d'administration CMS s'échelonne avec votre frontend. Pour les sites à fort trafic où le frontend et le CMS ont des besoins d'échelonnement très différents, vous voudrez peut-être envisager de les exécuter séparément.
Directus, étant un service séparé, sépare naturellement ces préoccupations. Votre frontend (que ce soit Next.js, Astro, ou n'importe quoi d'autre) se connecte à Directus via HTTP. C'est une architecture headless plus traditionnelle.
chez Social Animal, nous avons déployé les deux architectures pour des clients. L'approche Payload-in-Next.js fonctionne magnifiquement pour la plupart des sites marketing et applications de taille moyenne. Pour les configurations d'entreprise avec plusieurs consommateurs frontend, l'approche séparée de Directus peut être plus propre.
Tarification et licences en 2026
| Payload CMS | Directus | |
|---|---|---|
| Licence | MIT | GPL-3.0 (avec BSL pour les fonctionnalités Cloud) |
| Coût auto-hébergement | Gratuit | Gratuit |
| Hébergement cloud | À partir de $30/mo (Payload Cloud) | À partir de $29/mo (Directus Cloud) |
| Tier entreprise | Tarification personnalisée | Tarification personnalisée (à partir de ~$1 500/mo) |
| Fonctionnalités premium | Certaines fonctionnalités Cloud-only | Souscription Directus+ ($99/mo pour les extensions de marketplace) |
Les deux sont réellement open-source pour l'auto-hébergement. La licence MIT de Payload est plus permissive — vous pouvez l'intégrer dans des produits commerciaux sans restrictions. La licence GPL-3.0 de Directus signifie que les travaux dérivés doivent aussi être GPL, ce qui peut compter pour les produits SaaS.
Directus a introduit Directus+ fin 2025, une souscription qui déverrouille les extensions premium du marketplace et le support prioritaire. C'est optionnel mais certaines des extensions plus avancées (comme l'assistant de contenu IA) se trouvent derrière ce paywall.
Quand choisir lequel
Choisissez Payload CMS quand:
- Vous construisez un nouveau projet à partir de zéro (greenfield)
- Votre équipe est lourde en TypeScript et veut le schéma-en-code
- Vous utilisez Next.js et voulez l'intégration la plus étroite possible
- Vous avez besoin d'un contrôle d'accès complexe défini par code
- Vous voulez tout dans une unité déployable
- Vous appréciez la licence MIT
Choisissez Directus quand:
- Vous avez une base de données existante que vous avez besoin de gérer
- Votre équipe inclut des non-développeurs qui ont besoin de modifier les schémas
- Vous avez besoin de supporter plusieurs frontends (web, mobile, IoT) à partir d'un CMS
- Vous avez besoin d'un constructeur de flux/automatisation visuel
- Vous avez besoin d'un support de base de données large (MySQL, MSSQL, Oracle, etc.)
- Vous préférez le CMS comme un service indépendant et séparé
Si vous pesez ces options pour un projet headless et que vous voulez un second avis, nous faisons du consulting en architecture CMS headless et pouvons vous aider à choisir le bon outil avant d'être trois mois dans le mauvais.
Pour les projets utilisant Astro comme framework frontend, l'approche autonome de l'API de Directus s'associe naturellement, puisque Astro récupère les données au moment du build ou via des endpoints serveur. Payload fonctionne aussi, mais vous perdez l'avantage de l'API Local puisque Astro et Payload seraient des processus séparés.
FAQ
Payload CMS est-il vraiment gratuit en 2026 ?
Oui. Payload CMS est licencié MIT et entièrement gratuit pour l'auto-hébergement. Payload Cloud est leur service d'hébergement géré payant, mais le CMS lui-même — incluant toutes les fonctionnalités principales — est open source. Il n'y a pas de gates de fonctionnalités sur la version auto-hébergée.
Directus peut-il fonctionner avec une base de données existante sans la modifier ?
Généralement oui. Directus peut introspect une base de données existante et créer une couche de gestion par-dessus. Il ajoute quelques tables système (préfixées avec directus_) pour sa propre configuration, mais il ne modifie pas vos tables existantes. C'est l'un de ses plus forts différenciateurs.
Lequel est meilleur pour un développeur solo ?
Payload CMS a tendance à être le favori des développeurs solo qui sont à l'aise avec TypeScript. Le flux de travail code-first signifie que vous pouvez configurer les collections rapidement, et les types auto-générés réduisent le boilerplate. Directus est meilleur si vous voulez une interface visuelle pour le prototypage de schéma rapide sans écrire de fichiers de config.
Puis-je utiliser Payload CMS sans Next.js ?
À partir de Payload 3.x, Next.js est l'adaptateur principal et le panneau d'administration s'exécute sur Next.js. Cependant, les APIs REST et GraphQL fonctionnent avec n'importe quel frontend. Vous n'êtes pas verrouillé à Next.js pour votre site consumer-facing — vous avez juste besoin de Next.js pour exécuter l'admin Payload. Il y a eu des discussions communautaires sur des adaptateurs supplémentaires (comme Nuxt), mais rien d'officiel pour l'instant.
Comment Directus gère-t-il la localisation du contenu ?
Directus supporte les traductions au niveau des champs. Vous marquez les champs comme traduisibles, configurez vos langues, et Directus gère le stockage des traductions dans une table associée. L'API vous permet de demander du contenu dans des langues spécifiques via les paramètres ?fields et langue. C'est bien implémenté et a été stable pendant des années.
Lequel a un meilleur support de plugin/extension ?
Directus a un plus grand marketplace d'extensions, en particulier avec les ajouts Directus+. Vous pouvez construire des interfaces personnalisées, displays, endpoints, hooks, et modules. Le modèle d'extension de Payload est basé sur les remplacements de composants React et les plugins — c'est puissant mais l'écosystème est plus petit. Les plugins de Payload ont tendance à être plus ciblés (plugin SEO, form builder, redirects) tandis que les extensions de Directus couvrent une gamme plus large.
Y a-t-il une différence de performance pour les grands ensembles de données ?
Pour les ensembles de données avec des millions de lignes, les deux performent bien quand correctement indexés. Directus a un léger avantage sur la flexibilité brute des requêtes puisqu'il génère SQL plus directement à partir des requêtes API. La couche Drizzle ORM de Payload est efficace mais ajoute un petit coût d'abstraction. En pratique, votre tuning de base de données compte bien plus que quel CMS vous choisissez. Les deux supportent la mise en pool de connexions et peuvent fonctionner avec des répliques en lecture.
Puis-je migrer de l'un à l'autre plus tard ?
Vous pouvez, mais ce n'est pas trivial. Les données de contenu elles-mêmes (stockées dans PostgreSQL pour les deux) peuvent être migrées avec les outils standard de base de données. La partie plus difficile est de recréer vos définitions de schéma, vos règles de contrôle d'accès, et toute logique personnalisée. Si vous construisez pour une architecture headless, garder votre frontend découplé des APIs spécifiques au CMS (en utilisant une couche d'abstraction) rendra toute migration future de CMS significativement plus facile.