23/05/2026

Por que pausei meu CMS custom pra apostar no EmDash

Passei boas horas construindo um CMS na stack da Cloudflare (Workers + D1 + R2 + Hono) com Claude Code pra substituir o Keystatic. Funcionou. E mesmo assim resolvi pausar. Esse post conta o porquê, o que aprendi com a stack, e por que o EmDash chegou na hora certa.

Por que pausei meu CMS custom pra apostar no EmDash

Esse site usa Astro e implementei o Keystatic, e eu gosto bastante. Conteúdo no repo, admin leve, deploy via git. Pra projeto pessoal, recomendo sem hesitar.

Mas algumas coisas começaram a apertar quando pensei em rodar Keystatic em projetos de clientes da Toledo Interactive: ordenação ruim e sem persistir, sem drafts reais (precisa criar branch separado), sem armazenar dados, não tem como customizar muito o admin e os componentes custom dependem do @keystatic/astro que ainda não suporta Astro 6 até o momento de publicação desse post. Nenhum desses pontos é dealbreaker pra um site. Mas pra rodar cinco ou dez, vira atrito.

Em vez de pular pra outro CMS pronto, decidi construir o meu. Era pra ser projeto de aprendizado e ferramenta de produção ao mesmo tempo: rodar nas mesmas APIs que ofereço pros meus clientes (Workers, D1, R2), usar Claude Code o tempo todo como par de programação, e validar até onde dá pra ir com a stack da Cloudflare sem depender de SaaS de terceiro.

Foram aproximadamente 8 horas espalhadas ao longo de alguns dias. Cheguei num CMS funcional, deployado em cms.marciotoledo.com, com todo o conteúdo do site migrado pra dentro do D1. Funciona. E ainda assim, resolvi pausar antes de plugar ele no site público.

Esse post conta os dois lados. Primeiro o que eu construí (vale como referência técnica pra quem quer fazer algo parecido). Depois por que o EmDash chegou e fez sentido apostar nele em vez de seguir com o CMS.

A stack que escolhi pra construir o CMS

Decisão número um: nada de framework de CMS pronto (Payload, Strapi, Directus). A ideia era controlar 100% da superfície e aprender. Stack:

Bundle final do Worker: 158KB, 36KB gzipped. Bem dentro do limite do plano free (3MB).

O que ele faz hoje

FeatureStatus
Login com sessão de 30 dias (rate limit 10/min/IP)pronto
CRUD de posts com EasyMDE (markdown editor)pronto
Upload de imagens pro R2 inline no editorpronto
CRUD genérico de works, tools, skills, quotespronto
Drag-and-drop pra reordenar collectionspronto
Toggle PT/EN nos campos bilíngues, com persistência via localStoragepronto
Slug auto-gerado do título + botão pra regenerarpronto
API REST pública /api/v1/* com Bearer tokenpronto
Backup semanal automatizado via cron (D1 → R2 com retenção de 12)pronto
Botão “Publicar site” pra disparar deploy hook do Pagesarmado

Conteúdo migrado: 10 posts (com markdown + custom directives reescritas), 44 works, 2 tools, 2 skills, 29 quotes, 7 singletons. Tudo em D1, imagens em R2 com paths flat (media/foo.jpg, sem subpasta por slug pra desacoplar imagem do post).

O que aprendi construindo isso

Algumas coisas que só descobri colocando a mão.

A stack da Cloudflare é absurdamente boa pra esse caso. Cold start zero, latência baixa, custo previsível. O conjunto D1 + R2 + Workers cobre 100% do que um CMS pequeno precisa, sem precisar de Postgres, Redis, S3, ou qualquer outra peça externa. Pra projetos da Toledo Interactive (sites institucionais, blogs, landing com formulário), isso é o nível certo de complexidade.

Workers Free tem armadilhas reais. O limite de 10ms de CPU é mais apertado do que parece. Scrypt estoura. Markdown rendering pesado também (não cheguei a testar, mas vi gente reclamando). Pra um CMS read-mostly que serve HTML estático e API JSON, é tranquilo. Pra qualquer transformação CPU-intensa, plano pago é necessário.

Image Transformations da Cloudflare não funciona sobre origem externa no plano free. O /cdn-cgi/image/.../<url-externa> retorna 403. Solução: o bucket R2 vai ser montado como binding no Pages do site também, expondo em marciotoledo.com/media/*. Assim o helper de imagem do site continua usando path local e a transformação funciona.

Schema em código declarativo é poderoso. Cada singleton e cada collection do CMS é descrita por um objeto TypeScript ({ fields: [...], hasSlug: true, sortable: true }), e a UI inteira é gerada genericamente desse schema. Adicionar um campo novo é trocar uma linha, não escrever um form do zero. Esse é o padrão de Sanity e Payload, e funciona bem mesmo numa versão minimalista.

Claude Code mudou minha velocidade de desenvolvimento. Foram dias inteiros em que eu descrevia o que queria e ia validando o resultado, sem escrever quase nada de código manualmente. Pra projeto de aprendizado, vale principalmente porque eu ainda lia tudo e entendia o que estava sendo gerado. Pra projeto de produção crítica, talvez deixaria de fazer review-line-by-line e isso preocupa. Mas a aceleração é real.

Construir CMS é um buraco sem fundo. Eu cobri o básico. Falta: media library com busca, image cropping, versionamento de conteúdo, multi-user com permissões, 2FA, preview de drafts no site público, integração com forms de contato. Cada um desses é uma feature séria, com edge cases. A versão “boa o suficiente” pra Marcio Toledo não é a versão “boa o suficiente” pra clientes pagantes.

Aí o EmDash apareceu

A Cloudflare lançou o EmDash em abril de 2026. Não tinha radar pra ele quando comecei o projeto. Quando vi, foi um soco no estômago e ao mesmo tempo um alívio.

Vou listar exatamente por que ele bateu fundo:

  1. Mesma stack que eu escolhi. Astro + Workers + D1 + R2. Não um SaaS proprietário, não um Postgres caro. A infra que eu já entendo, no provedor que eu já uso.
  2. Open-source MIT. Sem licenciamento por site, sem cobrança por seat. Hospedando no Cloudflare, custo mínimo: $5/mês de Workers Paid pra ter os limites maiores e desbloquear features como Worker Loader (sandboxing de plugins). Sem surpresa no fim do mês.
  3. Spiritual successor do WordPress. Essa parte é importante pra mim. Tenho mais de uma década evitando WordPress (segurança, performance, manutenção, a experiência de admin que envelheceu mal). Sempre faltou um substituto sério pra quando o cliente precisa do “eu mesmo edito meu site” de verdade, sem ser Webflow ou Wix. Sanity é técnico demais pra cliente não-dev, Strapi é pesado demais pra hospedar, Payload é caro pra escalar. EmDash propõe ser o que o WordPress foi: o default razoável.
  4. Integração nativa com Astro. Uma linha no astro.config.mjs. O CMS roda no mesmo Worker do site, lê do mesmo D1, escreve no mesmo R2. Sem ponte, sem API entre eles.
  5. Admin pronto em /_emdash/admin. Schema vive na DB (não em código), seedado de um seed.json. Editar schema é editar JSON e rodar reseed. Tipo Strapi mas mais leve.
  6. MCP server embutido. Documentação acessível direto via Claude Code como ferramenta. Plus: ferramentas pra agentes IA interagirem com conteúdo do site direto da CLI.
  7. Plugin system com sandboxing. Webhooks, forms, integrações. Plugins rodam isolados em Dynamic Workers (no Cloudflare). Comunidade já tá publicando coisa interessante.
  8. 190 releases em ~1 ano. Ritmo de quem está entregando. 10k stars no GitHub. Beta declarado, mas com supply-chain hardening sério (cooldown de release, bloqueio de subdeps exóticos). Não é vibe-coded.

Resumindo: é literalmente o CMS que eu estava construindo, mas pronto, mantido por uma comunidade, com features que eu não ia ter tempo de fazer.

A conta de custo de oportunidade

A pergunta óbvia: você gastou várias horas (não muitas por causa do Claude Code) e vai jogar fora?

Não exatamente. A conta é outra.

Cenário A: continuar com o CMS custom.

Cenário B: pausar o CMS e apostar no EmDash.

A diferença é energia. Manter um CMS proprietário consome energia que eu prefiro gastar entregando projeto pra cliente.

O que faço agora

Pausei o CMS. Não deletei nada. O Worker continua no ar em cms.marciotoledo.com, com todo o conteúdo migrado, como referência e backup. O site do marciotoledo.com segue rodando em Keystatic em produção, intocado. A Fase 2 (refator pra consumir do CMS) está pausada por tempo indefinido.

Em paralelo, instalei o EmDash em um ambiente de testes e vou construir o site da agência nele de verdade. Daqui umas semanas, com EmDash debaixo da unha, decido se migro este site também ou se sigo no Keystatic enquanto o EmDash amadurece pra cobrir os casos mais complexos (i18n bilíngue por field, markdown com directives custom, design opinionado).

O que valeu

Mesmo pausando o projeto, valeu cada hora. O que ganhei:

Resumo

Construí um CMS custom em uma semana pra substituir o Keystatic, na stack Workers + D1 + R2 + Hono + Astro. Funcionou. Logo depois a Cloudflare lançou o EmDash, que é literalmente o mesmo CMS, pronto, open-source, com comunidade.

Pausei o meu, montei o EmDash em outro projeto da agência pra validar, e vou contribuir com a comunidade dele em vez de manter código que só eu conheço. O CMS custom continua no ar como referência. O site marciotoledo.com segue em Keystatic até a decisão final.

Não foi tempo perdido. Foi o melhor jeito de eu chegar com base própria pra entender o que um CMS sério precisa fazer, e por que vale apostar num projeto coletivo em vez de carregar o meu sozinho.

Referências

#cms #cloudflare #emdash #astro

Você pode me encontrar no: Github, Behance, LinkedIn, YouTube, Instagram, X ou por email [email protected]!

Se eu te ajudei de alguma forma e você quiser retribuir, pode me pagar um café ou ainda usar um dos meus links de indicação para abrir conta em serviços como Asaas, Bunny, Clara, assinar conteúdos gratuitos ou usar serviços recomendados.

© 2002 - 2026 | Marcio Toledo. Todos os direitos reservados. For LLMs