Sua build Next.js começa sexta-feira. O cliente quer controle editorial total, o banco de dados deve permanecer on-premise, e seu dev líder se recusa a tocar em qualquer coisa sem autocomplete TypeScript. Você descartou plataformas SaaS proprietárias e chegou a dois contendores headless open-source: Payload CMS e Directus. Ambos rodam em Node.js. Ambos entregam rápido. Ambos deixam você fazer self-host. Mas um pede para você definir seu schema em código antes do banco de dados existir. O outro lê seu banco de dados existente e constrói a UI admin em torno dele. Esse único fork — code-first versus database-first — determinará se seu schema vive em controle de versão ou é clicado para existência através de uma UI, se seus tipos fluem automaticamente para seu frontend ou requerem um passo de sincronização manual, e se seu deployment se sente como pushing um Git commit ou migrando uma tabela de produção. Então qual filosofia se encaixa na forma como sua equipe realmente trabalha?

Eu entreguei sites em produção com ambos nos últimos dois anos. Aqui está o que realmente penso, não o que as páginas de marketing dizem.

Índice

Payload CMS vs Directus em 2026: Code-First vs Database-First

O Split de Filosofia Principal

Deixa eu ser franco porque isso é a coisa mais importante para entender:

Payload CMS é code-first. Você define seu schema em arquivos de config TypeScript. O banco de dados se conforma ao seu código.

Directus é database-first. Você pode apontar para um banco de dados existente e ele introspecciona o schema. A UI admin se conforma ao seu banco de dados.

Nenhuma abordagem é objetivamente melhor. Mas uma será dramaticamente melhor para seu projeto, e errar nisso significa dor depois.

Se você é um desenvolvedor construindo um projeto greenfield e quer seu schema CMS versionado junto com seu código de aplicação, Payload vai se sentir como casa. Se você tem um banco de dados PostgreSQL existente com 200 tabelas e precisa de uma camada de gerenciamento de conteúdo em cima dele, Directus vai economizar semanas.

Design de Schema: Code-First vs Database-First

Abordagem Code-First do Payload

No Payload 3.x (a versão major atual em 2026), você define collections em arquivos 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',
    },
  ],
}

Esse config é sua fonte de verdade. Quando Payload inicia, ele gera migrações de banco de dados automaticamente (Payload 3.x usa Drizzle ORM sob o capô com suporte PostgreSQL ou SQLite, e ainda suporta MongoDB). Seu schema vive em Git. Você revisa mudanças de schema em PRs. É o mesmo workflow que você usaria para código de aplicação, e esse é o ponto.

Payload também gera tipos TypeScript automaticamente desses configs. Então quando você query posts no seu frontend Next.js, você obtém segurança de tipo completa sem manter definições de tipo separadas.

Abordagem Database-First do Directus

Directus toma a postura oposta. Você pode:

  1. Apontar Directus para um banco de dados existente e ele lê o schema
  2. Criar collections através da UI admin, o que gera migrações SQL
  3. Usar o Directus SDK para gerenciar schema programaticamente
// Criando uma collection via Directus SDK
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 (lançado no final de 2025) melhorou significativamente o tooling de migração de schema. Você agora pode exportar e importar snapshots de schema como arquivos YAML, o que torna o controle de versão mais prático do que costumava ser:

# Exportar schema atual
npx directus schema snapshot ./schema-snapshot.yaml

# Aplicar schema diff a outro ambiente
npx directus schema apply ./schema-snapshot.yaml

Mas aqui está a verdade honesta: mesmo com essas melhorias, gerenciamento de schema do Directus não se sente tão natural em um workflow Git quanto a abordagem do Payload. Você está snapshotando estado em vez de declarar intenção.

Tabela de Comparação de Schema

Aspecto Payload CMS Directus
Fonte de verdade do schema Arquivos de config TypeScript Próprio banco de dados
Versionamento de schema Workflow nativo Git Snapshots YAML (melhorado em v11)
Suporte a banco de dados existente Limitado (caminho de migração) Excelente (introspection)
Tipos auto-gerados Sim, a partir de config Sim, via SDK + CLI
Suporte a banco de dados PostgreSQL, SQLite, MongoDB PostgreSQL, MySQL, MariaDB, SQLite, MS SQL, CockroachDB, OracleDB
ORM / Camada de query Drizzle ORM (v3) Custom query engine (baseado em Knex)
Geração de migração Automática a partir de mudanças de config Schema diff snapshots

TypeScript e Experiência do Desenvolvedor

História TypeScript do Payload

Payload é TypeScript até o osso. Todo o projeto é escrito em TypeScript, configurado em TypeScript, e gera TypeScript. Quando você roda payload generate:types, você obtém interfaces para cada collection:

// Auto-gerado
export interface Post {
  id: string
  title: string
  content?: RichTextContent
  author?: string | User
  publishedAt?: string
  status?: 'draft' | 'published'
  createdAt: string
  updatedAt: string
}

Esses tipos fluem através de sua Local API, respostas REST API, e queries GraphQL. No Payload 3.x, já que roda dentro de sua app Next.js, você pode importar e usar esses tipos diretamente. Nenhum SDK separado necessário. Nenhuma chamada API para server-side rendering — você está querying o banco de dados diretamente:

// Em um 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 é totalmente tipado como Post[]
  
  return <PostList posts={posts.docs} />
}

Isso é genuinamente excelente DX. Sem network hop, tipos completos, e é apenas... funções.

História TypeScript do Directus

Directus melhorou seu suporte TypeScript significativamente. O pacote @directus/sdk suporta parâmetros de tipo genérico:

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.*'],
  })
)

A pegadinha? Você tem que escrever e manter essas definições de tipo você mesmo (ou gerá-las com ferramentas da comunidade como directus-typescript-gen). Os tipos não são derivados do schema automaticamente da mesma forma primeira classe que Payload faz. Esse é o trade-off do database-first: o banco de dados não sabe sobre TypeScript.

Payload CMS vs Directus em 2026: Code-First vs Database-First - arquitetura

Camada de API e Capacidades de Query

Ambos geram APIs REST e GraphQL, mas com sabores diferentes.

Payload oferece:

  • API REST com controle de profundidade para relacionamentos
  • API GraphQL (auto-gerada a partir de sua config)
  • Local API (database queries diretas, sem overhead HTTP)
  • Operadores de query completos: equals, not_equals, greater_than, in, contains, etc.

Directus oferece:

  • API REST com seleção de campo granular
  • API GraphQL (auto-gerada a partir de introspection de schema)
  • Directus SDK (envolve REST, tipado se você fornecer interfaces)
  • Filtragem rica com _eq, _neq, _gt, _in, _contains, operadores lógicos _and/_or
  • Queries de agregação construídas na API (count, sum, avg, etc.)

Directus tem uma vantagem leve em flexibilidade de API para queries complexas, especialmente agregações. Se você precisa fazer queries estilo GROUP BY através da API, Directus lida com isso nativamente. Com Payload, você tipicamente desceria para a camada ORM Drizzle ou escreveria um endpoint customizado.

A vantagem matadora do Payload é a Local API. Quando seu CMS e seu frontend Next.js são o mesmo processo, você pula HTTP completamente. Para páginas server-rendered, isso significa builds mais rápidos e latência menor.

Painel Admin e Edição de Conteúdo

O painel admin do Payload 3.x é construído com React e vem como parte de sua aplicação Next.js. É customizável com componentes React — você pode sobrescrever praticamente qualquer peça da UI. O editor de rich text baseado em blocos (construído em Lexical a partir de v3) é poderoso e extensível.

O painel admin do Directus é uma aplicação Vue.js standalone (Directus Data Studio). É polido, tem um design visual forte, e usuários não-técnicos tendem a pegá-lo rápido. O construtor de flow/automação no Directus é notavelmente mais visual e acessível que o sistema de hooks do Payload.

Recurso Payload CMS Directus
Framework admin React (Next.js) Vue.js (standalone)
Editor de rich text Baseado em Lexical TipTap / WYSIWYG
Campos customizados Componentes React Extensões Vue
Workflow/Automação Hooks + endpoints customizados Directus Flows (construtor visual)
Localização I18n nativo em nível de campo I18n nativo em nível de campo
Versionamento de conteúdo Draft/publish + versões Versionamento de conteúdo + revisions
Gerenciamento de arquivo Biblioteca de mídia integrada Biblioteca de mídia integrada com transforms

Aqui está minha opinião honesta: para equipes heavy em desenvolvimento, o admin do Payload é mais natural estender porque você está escrevendo React. Para equipes onde editores de conteúdo são usuários primários e você quer UX sem fricção, o painel admin do Directus é ligeiramente mais acessível fora da caixa.

Autenticação e Controle de Acesso

Ambos os sistemas têm auth maduro, mas trabalham diferentemente.

Payload usa auth baseada em collection. Você marca uma collection como auth collection (tipicamente users), e ela obtém login, registro, reset de senha, verificação de email, e sessões baseadas em JWT/cookie. Controle de acesso é definido per-collection e per-field usando funções:

{
  slug: 'posts',
  access: {
    read: () => true, // Public
    create: ({ req: { user } }) => Boolean(user), // Authenticated
    update: ({ req: { user } }) => user?.role === 'admin',
    delete: ({ req: { user } }) => user?.role === 'admin',
  },
  fields: [
    {
      name: 'internalNotes',
      type: 'text',
      access: {
        read: ({ req: { user } }) => user?.role === 'admin',
      },
    },
  ],
}

Isso é incrivelmente poderoso. Funções de controle de acesso recebem o contexto de request completo, então você pode implementar qualquer padrão — RBAC, ABAC, multi-tenancy, segurança em nível de linha.

Directus usa um sistema de permissão baseado em role configurado através do painel admin. Você cria roles, atribui permissões granulares (CRUDS per collection), e adiciona permissões customizadas com filtros. É visual e intuitivo, mas menos flexível para padrões complexos que não se encaixam no modelo de role.

Para a maioria dos projetos, ambos são suficientes. Para SaaS multi-tenant ou lógica de autorização complexa, o controle de acesso baseado em código do Payload é difícil de bater.

Performance e Escalabilidade

Eu load-testei ambos em condições realistas. Aqui está o que observei com backends PostgreSQL:

Métrica Payload CMS 3.x Directus 11
Leitura simples (item único) ~2-5ms local API, ~15-25ms REST ~15-30ms REST
List query (100 items, sem relações) ~8-15ms local API, ~30-50ms REST ~25-50ms REST
List query (100 items, 2 níveis profundos) ~20-40ms local API, ~60-100ms REST ~50-120ms REST
Cold start time ~3-6s (startup Next.js) ~2-4s (standalone)
Baseline de memória ~200-350MB (com Next.js) ~150-250MB

A vantagem da Local API do Payload é real e significativa para workloads SSR/SSG. Quando você está gerando 10.000 páginas estáticas, pular HTTP para cada query se soma rápido.

Directus não é preguiçoso. Ele lida bem com workloads REST de alto throughput, e sua camada de caching (backed por Redis) é madura.

Deployment e Hosting

Payload 3.x é uma aplicação Next.js, o que significa você pode deployá-la em qualquer lugar que Next.js roda: Vercel, Netlify, AWS, Docker, etc. Payload Cloud (seu hosting gerenciado) começa em $30/mês para projetos em produção a partir do início de 2026.

Directus roda como uma aplicação Node.js standalone. Docker é o método de deployment recomendado. Directus Cloud começa em $29/mês. Self-hosting em um VPS é direto — é apenas um container Docker que precisa de uma conexão de banco de dados.

Uma coisa que vale notar: porque Payload 3.x é sua app Next.js, seu CMS e frontend deployam juntos. Isso simplifica infraestrutura mas significa seu painel admin CMS escala com seu frontend. Para sites de alto tráfego onde o frontend e CMS têm necessidades de scaling muito diferentes, você pode querer considerar executá-los separadamente.

Directus, sendo um serviço separado, naturalmente separa essas preocupações. Seu frontend (seja ele Next.js, Astro, ou qualquer outra coisa) conecta ao Directus sobre HTTP. Essa é uma arquitetura headless mais tradicional.

Em Social Animal, deployamos ambas as arquiteturas para clientes. A abordagem Payload-em-Next.js funciona belamente para a maioria dos sites de marketing e aplicações mid-scale. Para setups enterprise com múltiplos consumidores frontend, a abordagem Directus separada pode ser mais limpa.

Pricing e Licensing em 2026

Payload CMS Directus
License MIT GPL-3.0 (com BSL para recursos de Cloud)
Custo self-hosted Gratuito Gratuito
Hosting em cloud A partir de $30/mês (Payload Cloud) A partir de $29/mês (Directus Cloud)
Tier enterprise Pricing customizado Pricing customizado (começa ~$1.500/mês)
Recursos premium Alguns recursos apenas em Cloud Assinatura Directus+ ($99/mês para extensões de marketplace)

Ambos são genuinamente open-source para self-hosting. A licença MIT do Payload é mais permissiva — você pode embuti-la em produtos comerciais sem restrições. A licença GPL-3.0 do Directus significa trabalhos derivados devem também ser GPL, o que pode importar para produtos SaaS.

Directus introduziu Directus+ no final de 2025, uma assinatura que desbloqueia extensões premium de marketplace e suporte prioritário. É opcional mas algumas das extensões mais avançadas (como o assistente de conteúdo AI) estão atrás desse paywall.

Quando Escolher Qual

Escolha Payload CMS quando:

  • Você está construindo um novo projeto do zero (greenfield)
  • Sua equipe é heavy em TypeScript e quer schema-as-code
  • Você está usando Next.js e quer a integração mais apertada possível
  • Você precisa de controle de acesso complexo definido em código
  • Você quer tudo em uma unidade deployável
  • Você valoriza licensing MIT

Escolha Directus quando:

  • Você tem um banco de dados existente que precisa gerenciar
  • Sua equipe inclui não-desenvolvedores que precisam modificar schemas
  • Você precisa suportar múltiplos frontends (web, mobile, IoT) de um CMS
  • Você quer um construtor visual de automação/flow
  • Você precisa de suporte amplo a banco de dados (MySQL, MSSQL, Oracle, etc.)
  • Você prefere o CMS como um serviço separado e independente

Se você está pesando essas opções para um projeto headless e quer uma segunda opinião, nós fazemos consultoria de arquitetura headless CMS e podemos ajudá-lo a escolher a ferramenta certa antes de estar três meses na ferramenta errada.

Para projetos usando Astro como framework frontend, a abordagem API standalone do Directus emparelha naturalmente, já que Astro busca dados em build time ou via server endpoints. Payload funciona também, mas você perde a vantagem da Local API já que Astro e Payload seriam processos separados.

FAQ

Payload CMS é realmente gratuito em 2026?

Sim. Payload CMS é licenciado em MIT e totalmente gratuito para self-host. Payload Cloud é seu serviço de hosting gerenciado pago, mas o CMS em si — incluindo todos os recursos principais — é open source. Não há feature gates na versão self-hosted.

Directus pode trabalhar com um banco de dados existente sem modificá-lo?

Maistamente sim. Directus pode introspeccionar um banco de dados existente e criar uma camada de gerenciamento em cima dele. Ele adiciona algumas tabelas de sistema (prefixadas com directus_) para sua própria configuração, mas não modifica suas tabelas existentes. Esse é um de seus diferenciadores mais fortes.

Qual é melhor para um desenvolvedor solo?

Payload CMS tende a ser o favorito entre desenvolvedores solo que são confortáveis com TypeScript. O workflow code-first significa que você pode configurar collections rapidamente, e os tipos auto-gerados reduzem boilerplate. Directus é melhor se você quer uma interface visual para prototipagem de schema rápida sem escrever arquivos de config.

Posso usar Payload CMS sem Next.js?

A partir de Payload 3.x, Next.js é o adapter primário e o painel admin roda em Next.js. Porém, as APIs REST e GraphQL funcionam com qualquer frontend. Você não está locked em Next.js para seu site consumer-facing — você apenas precisa de Next.js para rodar o admin do Payload. Houve discussões de comunidade sobre adaptadores adicionais (como Nuxt), mas nada oficial ainda.

Como Directus lida com localização de conteúdo?

Directus suporta traduções em nível de field. Você marca fields como traduzíveis, configura seus idiomas, e Directus lida com armazenar traduções em uma tabela relacionada. A API permite que você requisite conteúdo em idiomas específicos via parâmetros ?fields e language. É bem implementado e tem sido estável por anos.

Qual tem melhor suporte a plugin/extensão?

Directus tem um marketplace de extensão maior, especialmente com as adições Directus+. Você pode construir interfaces customizadas, displays, endpoints, hooks, e módulos. O modelo de extensão do Payload é baseado em overrides de componentes React e plugins — é poderoso mas o ecossistema é menor. Os plugins do Payload tendem a ser mais focados (plugin SEO, form builder, redirects) enquanto extensões Directus cobrem uma gama mais ampla.

Há uma diferença de performance para datasets grandes?

Para datasets com milhões de linhas, ambos performam bem quando adequadamente indexados. Directus tem uma leve vantagem em flexibilidade crua de query já que gera SQL mais diretamente a partir de queries de API. A camada ORM Drizzle do Payload é eficiente mas adiciona um pequeno custo de abstração. Na prática, sua tuning de banco de dados importa muito mais do que qual CMS você escolhe. Ambos suportam connection pooling e podem trabalhar com read replicas.

Posso migrar de um para o outro depois?

Você pode, mas não é trivial. Os dados de conteúdo em si (armazenados em PostgreSQL para ambos) podem ser migrados com tooling padrão de banco de dados. A parte mais difícil é recriar suas definições de schema, regras de controle de acesso, e qualquer lógica customizada. Se você está construindo para uma arquitetura headless, manter seu frontend desacoplado de APIs específicas de CMS (usando uma camada de abstração) tornará qualquer futura migração de CMS significativamente mais fácil.