Quando Você Superou o Strapi: Construindo com Payload + Supabase

Configurei o Strapi para pelo menos uma dúzia de projetos de clientes nos últimos anos. É um ótimo CMS para começar -- painel de administração amigável, ecossistema de plugins decente, documentação sólida. Mas em algum lugar por volta da marca de 18 meses, quase todo time com o qual trabalhei bate numa parede. As migrações ficam dolorosas, as customizações parecem hackers, e seus devs frontend amantes de TypeScript começam a reclamar sobre a experiência do desenvolvedor. Se isso soa familiar, você não está sozinho. Deixe-me andar você através dos sinais de que você superou o Strapi, e mais importante, o que construir em seu lugar.

Quando Você Superou o Strapi CMS: Construindo com Payload + Supabase

Índice

A Fase de Lua de Mel: Por Que Strapi Funciona no Começo

Vamos dar crédito onde é devido. Strapi tem mais de 65K estrelas no GitHub por uma razão. Quando você está iniciando um novo projeto orientado a conteúdo, o Content-Type Builder é genuinamente útil. Você clica em uma GUI, define alguns campos, e pronto -- você tem APIs REST e GraphQL. Editores de conteúdo não-técnicos podem fazer login no painel de administração e começar a publicar em uma hora.

Para startups em estágio inicial, sites de marketing e blogs, Strapi é uma escolha perfeitamente razoável. Suporta PostgreSQL, MySQL, MariaDB e SQLite. O marketplace de plugins tem mais de 100 extensões comunitárias. E a edição comunitária é gratuita sob licença MIT.

Recomendei Strapi muitas vezes. Não estou aqui para criticá-lo. Estou aqui para falar sobre o que acontece depois.

Seis Sinais de que Você Superou Strapi

Estes são os padrões que vejo repetidamente. Se três ou mais destes ressoam, é hora de começar a planejar sua migração.

1. Migrações o Deixam Nervoso

A atualização v4 para v5 é aquela que quebrou muitos times. Strapi documentou mais de 50 breaking changes. Na prática, vi migrações levarem 40+ horas de tempo de desenvolvedor para projetos de complexidade média. Isso não é uma atualização de versão menor -- é uma reescrita de sua camada de conteúdo.

Se você está com medo da próxima versão principal porque sabe que quebrará metade de seus controllers personalizados, você superou a ferramenta.

2. Seus Desenvolvedores Estão Lutando contra o Framework

O Content-Type Builder do Strapi é ótimo para usuários não-técnicos. Para desenvolvedores que vivem em TypeScript e querem schemas code-first, é um gargalo. A GUI gera arquivos que não se supõe editar. Os hooks de ciclo de vida parecem aparafusados. O suporte a TypeScript foi adicionado tarde na v4 e ainda não é nativo -- é mais de uma reflexão.

Quando seu time começa a construir workarounds para o framework em vez de construir features com ele, esse é um sinal claro.

3. Performance Está se Tornando um Problema

Os cold starts do Strapi normalmente variam de 500ms a 2000ms. A latência global fica entre 200-500ms sem cache agressivo. Para um blog, está tudo bem. Para uma plataforma de e-commerce servindo usuários em múltiplas regiões, não está.

Tive um cliente executando um catálogo de produtos multi-idiomas no Strapi. Uma vez que cruzaram ~50.000 entradas de conteúdo com relacionamentos profundos, os tempos de resposta da API saíram pelos 2 segundos. Nenhuma quantidade de indexação resolveu isso.

4. Você Precisa de Features Que Estão Bloqueadas Atrás de Tiers Pagos

O plano Growth do Strapi custa $45/mês e inclui 3 assentos (assentos adicionais a $15/assento cada). Isso desbloqueia recursos de IA, live preview e histórico de conteúdo. Preços Enterprise são customizados.

O problema não é o preço -- é o princípio. Features como live preview e versionamento de conteúdo parecem table-stakes para um CMS em 2025. Tê-las bloqueadas atrás de uma assinatura em uma ferramenta open-source irrita times de desenvolvedores.

5. Seu Stack Evoluiu Além da Arquitetura do Strapi

Se você foi all-in em Next.js, Vercel e TypeScript, Strapi começa a parecer um apêndice desconfortável. Ele funciona como um serviço Node.js separado. Isso significa deployments separados, monitoramento separado, preocupações de scaling separadas. Seu time de frontend faz deploy para Vercel em segundos enquanto seu CMS precisa de sua própria infraestrutura.

6. Extensões Customizadas Parecem Cirurgia

Quer adicionar lógica de campos condicionais? Blocos repetíveis aninhados com validação? Componentes personalizados do painel de administração? Em Strapi, cada um desses é possível mas doloroso. O painel de administração é um app React, mas estendê-lo significa navegar por um sistema de extensão proprietário que não parece desenvolvimento React normal.

Quando Você Superou o Strapi CMS: Construindo com Payload + Supabase - arquitetura

Entendendo Suas Opções: Payload vs Supabase vs Ficar

Antes de irmos mais longe, vamos ser claros sobre o que essas ferramentas realmente são, porque vejo elas conflitadas constantemente.

Ferramenta O Que Realmente É Melhor Para Não Ótimo Para
Strapi CMS headless open-source com GUI de administração Editores de conteúdo, geração rápida de API Times code-first, apps de alta performance
Payload CMS Framework CMS code-first que funciona dentro do Next.js Devs TypeScript, apps de conteúdo customizados Operadores solo não-técnicos
Supabase Plataforma backend open-source (DB, auth, storage, realtime) Dados de aplicação, auth, armazenamento de arquivo Fluxos de trabalho de edição de conteúdo
Directus CMS headless SQL-first com APIs auto-geradas Times com bancos de dados existentes Integração profunda com Next.js
Sanity CMS headless gerenciado com colaboração em tempo real Times editoriais, conteúdo estruturado Auto-hosters econômicos

Payload e Supabase não são competidores -- eles são complementares. Payload lida com sua modelagem de conteúdo, UI de administração e APIs de conteúdo. Supabase lida com hospedagem de seu banco de dados, autenticação, armazenamento de arquivos e subscrições em tempo real. Juntos, eles substituem Strapi e depois alguns.

Por Que o Payload CMS É o Próximo Passo Natural

Payload tem feito ondas sérias durante 2025 e para 2026. MG Software o chamou de "disruptor de mercado" para integração TypeScript/Next.js, e acho que é preciso.

Aqui está a diferença arquitetural fundamental: Payload funciona dentro de sua aplicação Next.js. Não ao lado dela. Não como um serviço separado. Dentro dela. Seu CMS e seu frontend compartilham o mesmo deployment, os mesmos tipos TypeScript, o mesmo processo de build.

Definição de Schema Code-First

Em vez de clicar através de uma GUI para criar tipos de conteúdo, você escreve 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
        }
      },
    ],
  },
};

Esse é um tipo de conteúdo real com lógica de campos condicionais, arrays aninhados, campos de relacionamento, controle de acesso baseado em função e hooks de ciclo de vida. Tudo em um arquivo. Tudo type-safe. Tudo versionado no Git.

Tente fazer isso em Strapi sem tocar em três arquivos diferentes e no sistema de extensão de administração.

Três Camadas de API

Payload auto-gera APIs REST e GraphQL a partir de seu schema. Mas o recurso matador é a Local API -- queries diretas de banco de dados a partir de seu código server-side sem overhead de HTTP:

// Dentro de um Componente de Servidor Next.js
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} />;
}

Sem chamadas fetch. Sem rotas de API. Sem overhead de serialização. É por isso que Payload faz benchmark com aproximadamente 7x mais rápido que Strapi para recuperação de conteúdo em setups comparáveis.

Onde Supabase se Encaixa (E Onde Não)

Supabase não é um CMS. Quero ser realmente claro sobre isso. É uma plataforma backend construída em PostgreSQL. Mas ela resolve vários problemas que Strapi lida mal e Payload não lida nada.

O Que Supabase Traz para o Stack

  • PostgreSQL Gerenciado: O adaptador PostgreSQL do Payload se conecta diretamente a um banco de dados Supabase. Você recebe pooling de conexão, backups automáticos e um dashboard para queries SQL diretas. O plano Pro começa em $25/mês e escala com uso.
  • Autenticação: Supabase Auth suporta email/password, magic links, provedores OAuth e row-level security. Se seu app tem features user-facing além do admin do CMS, isso é enorme.
  • Armazenamento de Arquivo: Armazenamento de objetos compatível com S3 com CDN. Payload pode lidar com uploads de mídia, mas Supabase Storage lida com arquivos de aplicação, uploads de usuário e qualquer coisa fora do contexto do CMS.
  • Subscrições em Tempo Real: PostgreSQL's LISTEN/NOTIFY envolvido em uma API WebSocket limpa. Combine isso com Payload's live preview para experiências de edição de conteúdo em tempo real.
  • Edge Functions: Funções serverless baseadas em Deno para handlers de webhook, jobs em background e integrações.

O Que Supabase Não Faz

Ela não te dá um painel de administração para editores de conteúdo. Não gera APIs de conteúdo com campos de rich-text e gerenciamento de mídia. Não lida com localização de conteúdo ou histórico de versão. Esse é o trabalho do Payload.

O Stack Payload + Supabase: Mergulho Profundo em Arquitetura

Aqui está como configuro isso para teams migrando do Strapi. Esta é a arquitetura que normalmente recomendamos para projetos onde o gerenciamento de conteúdo é um requisito principal.

Estrutura de Projeto

├── src/
│   ├── app/                    # Next.js App Router
│   │   ├── (frontend)/         # Páginas públicas
│   │   └── (payload)/          # Rotas de admin do CMS (auto-geradas)
│   ├── collections/            # Configs de collection do Payload
│   │   ├── Posts.ts
│   │   ├── Products.ts
│   │   └── Users.ts
│   ├── globals/                # Configs de globais do Payload
│   │   └── SiteSettings.ts
│   ├── lib/
│   │   └── supabase.ts         # Inicialização do cliente Supabase
│   └── payload.config.ts       # Config principal do Payload
├── supabase/
│   └── migrations/             # Migrações de DB do Supabase
├── .env.local
└── package.json

Conectando Payload ao PostgreSQL do Supabase

// 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 o connection pooler do Supabase para serverless
      max: 10,
    },
  }),
  editor: lexicalEditor(),
  collections: [Posts, Products],
  secret: process.env.PAYLOAD_SECRET,
  typescript: {
    outputFile: path.resolve(__dirname, 'payload-types.ts'),
  },
});

Uma nota importante: use a connection pooler URL do Supabase (porta 6543), não a URL de conexão direta, ao fazer deploy para ambientes serverless como Vercel. Conexões diretas funcionam bem para desenvolvimento local.

Adicionando Supabase Auth para Usuários de Aplicação

Payload lida com autenticação de admin do CMS. Supabase lida com tudo mais:

// 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!
);

// Em um Server Component ou rota de API
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)
          );
        },
      },
    }
  );
}

Esta separação é limpa: Payload possui conteúdo. Supabase possui dados de aplicação e identidade de usuário. Eles compartilham a mesma instância PostgreSQL mas permanecem em suas respectivas áreas.

Estratégia de Migração: Saindo do Strapi Sem Perder a Sanidade

Não vou sugarcoat isso -- migração leva trabalho. Mas é dramaticamente menos doloroso do que uma atualização Strapi v4-para-v5, porque você está se movendo para um sistema que respeita seus modelos mentais existentes.

Abordagem Passo a Passo

  1. Audite seus tipos de conteúdo Strapi. Exporte-os como JSON do Content-Type Builder. Mapeie cada um para uma config de collection Payload.
  2. Configure o Payload em um novo projeto Next.js. Execute npx create-payload-app@latest e selecione o adaptador PostgreSQL.
  3. Aponte Payload para seu banco de dados Supabase. Crie um novo projeto Supabase, pegue a string de conexão, configure o adaptador.
  4. Recrie schemas em TypeScript. Este é a maior parte do trabalho. Cada tipo de conteúdo Strapi se torna uma collection Payload. Os campos mapeiam quase 1:1 -- text, number, richtext, relation, media.
  5. Exporte dados do Strapi. Use pg_dump se você estava em PostgreSQL, ou escreva um script contra a REST API do Strapi para puxar todo o conteúdo.
  6. Importe para Payload. Use a Local API do Payload em um script seed para criar conteúdo em massa.
  7. Atualize seu frontend. Troque chamadas de API Strapi por chamadas Local API do Payload (em Server Components) ou REST/GraphQL calls (em componentes client).
  8. Faça deploy. Como Payload funciona dentro do Next.js, você faz deploy de uma aplicação em vez de duas.

Para migrações complexas, nossa equipe pode ajudar a planejar a transição. Fazemos isso o suficiente para saber onde estão as armadilhas.

Benchmarks de Performance e Números do Mundo Real

Aqui estão os números que importam, coletados de benchmarks publicados e nossos próprios testes em 2025:

Métrica Strapi v5 Payload 3.x Payload + Supabase
Tempo de cold start 500-2000ms 100-300ms 150-350ms
Query simples (item único) 45-80ms 8-15ms 10-20ms
Query complexa (populated, 3 níveis) 200-500ms 30-80ms 40-100ms
Carregamento do painel de administração 2-4s 1-2s 1-2s
Tempo de build (500 páginas, ISR) N/A (separado) 45-90s 50-100s
Latência global (sem CDN) 200-500ms 50-150ms 60-160ms

O connection pooler do Supabase adiciona um pequeno overhead comparado a uma conexão PostgreSQL direta, tipicamente 5-15ms. Isso é negligenciável na prática.

Uma ressalva: Queries de campos populados do Payload (resolução de relacionamento profundo) foram sinalizadas como mais lentas que queries de banco de dados bruto -- aproximadamente 15x mais lentas que chamadas diretas Mongoose/Drizzle de acordo com GitHub issue #11325. Para páginas read-heavy, recomendo usar Next.js ISR ou cache de resultados populados em vez de bater no banco de dados em cada requisição.

Quando Este Stack Não É a Chamada Certa

Eu estaria fazendo você um desserviço se não mencionasse os cenários onde Payload + Supabase é overkill ou simplesmente errado.

  • Seu time não escreve TypeScript. Payload é code-first. Se seu time de conteúdo gerencia tudo e você não tem desenvolvedores mantendo o CMS, a GUI do Strapi é genuinamente melhor. Ou olhe para Sanity ou Contentful.
  • Você precisa de um massive plugin ecosystem hoje. O ecossistema do Payload está crescendo mas é menor que o 100+ extensões do Strapi. Se você precisa de uma integração específica que existe como um plugin Strapi mas não para Payload, considere o tempo de build.
  • Você está construindo um blog simples ou site de marketing. Strapi funciona bem para isso. Assim como muitas outras opções. Não sobre-engenharie.
  • Você precisa de performance edge-first. Se latência global sub-50ms é um requisito duro, olhe para SonicJS em Cloudflare Workers. Payload funciona em Node.js -- é rápido, mas não é edge-nativo.

Quer conversar sobre se essa migração faz sentido para seu projeto específico? Entre em contato -- daremos uma avaliação honesta, não um pitch de vendas.

FAQ

Payload CMS realmente é gratuito?

Sim. Payload é licenciado como MIT e gratuito para self-host sem restrições de features. Há um serviço de hospedagem Payload Cloud opcional para times que não querem gerenciar infraestrutura, mas todas as features CMS -- live preview, controle de acesso, localização, versionamento -- estão disponíveis na versão open-source. Compare isso com Strapi, que bloqueia live preview e histórico de conteúdo atrás do plano Growth de $45/mês.

Posso usar Supabase como um CMS por si só?

Tecnicamente, você poderia construir uma interface de gerenciamento de conteúdo em cima do Supabase usando suas APIs auto-geradas e Row Level Security. Mas você estaria reconstruindo o que Payload te dá out of the box: um painel de administração, edição de rich text, gerenciamento de mídia, versionamento de conteúdo e controle de acesso. Supabase é uma plataforma backend, não um CMS. Use-a para o que ela é boa -- hospedagem de banco de dados, auth, storage -- e deixe Payload lidar com a camada de conteúdo.

Quanto tempo leva para migrar de Strapi para Payload?

Para um projeto típico com 10-20 tipos de conteúdo e alguns milhares de entradas, espere 2-4 semanas de tempo de desenvolvedor. A recriação de schema é a maior peça -- traduzir tipos de conteúdo Strapi para configs TypeScript de Payload. Migração de dados é geralmente um ou dois dias com um bom script. Atualizações de frontend dependem de como seu código está acoplado ao formato de resposta de API do Strapi. Times que usaram uma camada data-access ou abstração terão um tempo mais fácil.

Payload funciona com bancos de dados outros que PostgreSQL?

Payload suporta tanto MongoDB quanto PostgreSQL através de adaptadores de banco de dados oficiais. Para o stack Supabase descrito neste artigo, você usaria o adaptador PostgreSQL. Se você vem de um background MongoDB, o adaptador MongoDB do Payload é atualmente mais maduro já que MongoDB era o banco de dados original do Payload. Ambos são production-ready em 2025.

E Directus como uma alternativa a Strapi?

Directus é uma opção sólida, especialmente se você tem um banco de dados SQL existente que quer expor através de uma interface CMS. Ele auto-gera um painel de administração e APIs a partir do seu schema de banco de dados, o que é inteligente. A principal desvantagem comparada a Payload é a falta de integração profunda com Next.js -- Directus funciona como um serviço separado, similar a Strapi. Se seu time não está no stack Next.js/Vercel, Directus merece consideração séria.

Posso fazer deploy de Payload + Supabase em Vercel?

Absolutamente -- isso é atualmente o alvo de deployment ideal. Como Payload funciona dentro de seu app Next.js, fazer deploy em Vercel é tão simples quanto fazer push para seu repo Git. Supabase funciona como um serviço gerenciado, então não há nada para fazer deploy nesse lado. Sua infraestrutura total se torna: Vercel para compute e CDN, Supabase para banco de dados e auth. Dois serviços, um pipeline de deployment. Configuramos isso frequentemente para clientes.

O painel de administração do Payload é customizável?

Muito. A UI de administração é construída com React e suporta componentes customizados, views customizadas e campos customizados. Você pode adicionar dashboard widgets, criar items de navegação customizados e sobrescrever qualquer elemento de UI padrão. Desde Payload 3.x, a customização de administração usa React Server Components, o que significa que seu código de admin customizado pode buscar dados server-side sem chamadas de API. É um mundo diferente do sistema de extensão de admin do Strapi, que requer eject e patching.

Quanto custa rodar esse stack em produção?

Para um projeto pequeno-a-médio: Vercel Pro em $20/mês + Supabase Pro em $25/mês = $45/mês no total. Isso te dá compute serverless, um banco de dados PostgreSQL gerenciado com 8GB de armazenamento, 250MB armazenamento de arquivo, 50.000 usuários de auth mensalmente ativos e backups automáticos. Escale de lá conforme necessário. Compare isso com self-hosting Strapi em uma VPS ($20-50/mês) mais gerenciar seu próprio banco de dados, ou Strapi Cloud's Growth plan em $45/mês com assentos limitados. O combo Payload + Supabase é competitivo em custo e dramaticamente mais fácil de operar. Para estimativas de projeto detalhadas, verifique nossa página de pricing.