Pontos-chave
- Um CMS sem interface (headless) armazena o conteúdo separadamente da interface do utilizador, e o Node.js permite-te decidir exatamente como esse conteúdo é obtido e apresentado.
- Entre as opções populares de CMS «headless» compatíveis com o Node.js, contam-se plataformas auto-hospedadas, como o Strapi e o Payload, e plataformas hospedadas, como o Contentful e o Sanity.
- Este guia mostra como criar um backend funcional para um blogue com o Express, o EJS e o Contentful e, depois, testá-lo localmente.
- O projeto final é implementado diretamente a partir do GitHub, utilizando a hospedagem gerida do Node.js da Cloudways.
Num CMS sem interface (headless), o conteúdo é armazenado e gerido separadamente da interface do utilizador. Muitos blogs e sites de comércio eletrónico modernos funcionam assim. O conteúdo fica no CMS e é enviado para o que quer que seja que o exiba através de uma API.
O Node.js combina naturalmente com uma configuração «headless», porque não vem com nenhuma regra de renderização incorporada. És tu que decides como o conteúdo é obtido e apresentado, quer se trate de uma página renderizada pelo servidor, de uma API JSON para uma aplicação móvel ou de qualquer outra coisa que queiras criar com base nisso.
Neste blogue, vou explicar por que é que faz sentido combinar o Node.js com um CMS headless, vou dar uma vista de olhos a algumas das opções de CMS mais populares que existem e, depois, vou criar um pequeno projeto para mostrar como funciona na prática. Por fim, vou implementar tudo num servidor Cloudways ativo.
- Por que usar o Node.js com um CMS sem interface gráfica?
- Opções populares de CMS sem interface para o Node.js
- Como criar um blogue «headless» usando o Node.js
- O que vou usar
- Passo 1: Configurar o CMS sem interface gráfica (Contentful)
- Passo 2: Configurar o projeto Node.js
- Passo 3: Obter dados e criar uma interface de utilizador simples
- Passo 4: Enviar o projeto para o GitHub
- Passo 5: Ligar o Cloudways ao GitHub
- Passo 6: Implementar a aplicação e colocá-la em funcionamento
- O momento da verdade
- Conclusão
Por que usar o Node.js com um CMS sem interface gráfica?
A principal razão pela qual eu optaria pelo Node.js puro nesta situação é o controlo. Não há nenhuma estrutura que dite como o conteúdo tem de ser obtido ou apresentado; és tu que escreves a lógica, exatamente da forma que o teu projeto precisa.
Como o Node.js não está vinculado a nenhuma abordagem específica de front-end, o mesmo back-end pode servir conteúdo da forma que quiseres. Podes renderizar páginas HTML completas no servidor, disponibilizar o conteúdo como uma API JSON simples para um front-end ou uma aplicação móvel separada, ou fazer as duas coisas a partir de uma única base de código.
Além disso, é leve. Não precisas de usar um framework de front-end completo e todas as suas ferramentas de compilação só para mostrar uma lista de publicações de blogue; basta um pequeno servidor Express e um motor de modelos para obteres um resultado funcional e pronto para produção.
E, tal como em qualquer configuração «headless», tens a flexibilidade de manter tudo separado. O CMS trata da criação e do armazenamento de conteúdos. O teu backend Node.js trata da lógica, da formatação e da entrega. Nenhum dos dois interfere com o outro.
Opções populares de CMS sem interface para o Node.js
Antes de começares a construir, vale a pena saberes o que existe realmente no mercado, já que o termo «CMS headless» abrange uma gama bastante ampla de ferramentas.
- Strapi — De código aberto e auto-hospedado, o que significa que todo o CMS funciona como a tua própria aplicação Node.js. Vem com um painel de administração completo pronto a usar, além de um ecossistema de plugins caso precises de o ampliar mais tarde.
- Payload — Nativo do TypeScript e com abordagem «code-first», defines o teu esquema diretamente no código. Foi desenvolvido com um forte enfoque nos fluxos de trabalho do React e do Next.js, embora também funcione bem fora desse contexto.
- KeystoneJS — Gera automaticamente uma API GraphQL a partir da definição do teu esquema. O código de rotina é mínimo, se já gostas de consultar dados com o GraphQL.
- Contentful — É totalmente alojado, por isso não tens de gerir nenhum servidor. Vem com modelos prontos a usar, incluindo o modelo «Blog» que vou usar no miniprojeto abaixo.
- Sanity — Também está alojado, com edição colaborativa em tempo real integrada. Suporta tanto a sua própria linguagem de consulta (GROQ) como o GraphQL, dependendo da tua preferência.
No miniprojeto de que vou falar a seguir, vou usar o Contentful, principalmente para manter o foco na parte do Node.js da construção, em vez de perder tempo a montar e configurar um CMS inteiro do zero.
Como criar um blogue «headless» usando o Node.js
Para te mostrar como isto funciona na prática, vou criar um mini-projeto: um backend simples para um blogue que recupera artigos de um CMS e os apresenta como páginas HTML simples, usando o Express.
O que vou usar
- Node.js
- VS Code
- Contentful (plano gratuito)
- Express e EJS
Passo 1: Configurar o CMS sem interface gráfica (Contentful)
Antes de escrever qualquer código de backend, preciso de um sítio onde possa guardar o conteúdo do blogue. Vou usar o plano gratuito do Contentful para isso.
Quando me registo, o Contentful dá-me a opção de começar a partir de um modelo, e vou escolher o modelo «Blog» para não ter de criar uma estrutura de conteúdo do zero.
Para confirmar se está tudo configurado como eu esperava, vou à separador «Modelo de Conteúdo » e ver o que já lá está.
O que eu preciso mesmo é da página «Publicação no blogue», que tem campos como o título, os metadados de SEO e o corpo do conteúdo principal.

A seguir, vou passar para o separador «Conteúdo ». Como usei o modelo, o Contentful já deve ter criado algumas publicações de blogue de exemplo para mim. Só preciso de me certificar de que o estado delas aparece como «Publicado», pois é isso que faz com que possam ser recuperadas através da API.

Está tudo a aparecer como publicado, por isso essa parte já está resolvida.
Última coisa antes de sair do Contentful: preciso das minhas chaves de API para que a minha aplicação Node.js consiga comunicar com o Contentful. Vou a Definições > Chaves de API, clico em «Adicionar chave de API», dou-lhe um nome para me lembrar mais tarde para que serve e gerar as chaves.

Vou deixar este separador aberto, porque daqui a pouco vou precisar de copiar o ID do Space e o token de acesso à API de Entrega de Conteúdo.
Passo 2: Configurar o projeto Node.js
Agora, quanto ao backend propriamente dito. Antes de poder fazer qualquer coisa, preciso de ter o Node.js instalado no meu computador.
Estou a trabalhar no portátil do escritório, que tem restrições de TI, por isso, como de costume, vou descarregar a versão binária independente do Node.js do site nodejs.org, em vez de usar um instalador normal.

Assim que estiver descarregado, vou descompactá-lo na minha pasta «Downloads».

Abrir a pasta do projeto no Prompt de Comandos
Vou criar uma pasta para este projeto no meu ambiente de trabalho e vou chamá-la simplesmente de headless-blog.
Depois, vou abrir o Prompt de Comando e ir para essa pasta:
cd C:\Users\abdulrehman\Desktop\headless-blog

Configurar o Prompt de Comando para o executável do Node
Como o Prompt de Comando não faz ideia de onde é que o Node está mesmo instalado no meu computador, vou indicar-lhe o caminho manualmente:
define PATH=%PATH%;C:\Users\abdulrehman\Downloads\node-v24.18.0-win-x64\node-v24.18.0-win-x64

Para ter a certeza de que está mesmo a funcionar, vou executar:
node -v npm -v
Ambos os comandos mostram os números das versões, por isso já posso continuar.

Criar o projeto Node.js
Primeiro, vou criar um projeto simples em Node.js:
npm init -y

Depois, vou instalar tudo o que este projeto realmente precisa: o Express para gerir o encaminhamento, o EJS para renderizar HTML, o SDK oficial do Contentful para recuperar conteúdo, um renderizador de texto rico para converter o formato de conteúdo do Contentful em HTML e o dotenv para gerir as minhas chaves de API localmente.
npm install express ejs contentful @contentful/rich-text-html-renderer dotenv

Passo 3: Obter dados e criar uma interface de utilizador simples
Agora vou abrir a pasta do meu projeto no VS Code. Para isso, vou a Ficheiro > Abrir Pasta e seleciono a minha pasta «headless-blog».

Pronto, já abri o meu projeto no VS Code, por isso agora é hora de começar mesmo a escrever a lógica do backend.
Proteger as chaves da API
A primeira coisa que quero fazer é guardar as chaves do Contentful num local seguro do projeto. Para isso, na raiz da pasta do meu projeto, vou criar um novo ficheiro chamado .env e colar o seguinte:
CONTENTFUL_SPACE_ID=your_space_id_here CONTENTFUL_ACCESS_TOKEN=your_content_delivery_api_access_token_here

Agora, como estas são as minhas chaves reais, não quero que fiquem no meu repositório público do GitHub, à vista de toda a gente. Para evitar isso, vou criar mais um ficheiro na raiz do meu projeto chamado .gitignore e colar o seguinte:
node_modules .env
Isto diz ao Git para ignorar ambos sempre que eu fizer um push do meu projeto. O «node_modules» porque são só pacotes descarregados, não há motivo para os enviar. E o «.env» porque é o ficheiro que contém as minhas chaves reais do Contentful, por isso, ao deixá-lo de fora, elas nunca acabam por ficar num sítio público.
Configurar o Contentful Client
A seguir, preciso de algo que ligue mesmo a minha aplicação ao Contentful. Para isso, vou criar uma pasta chamada «lib» na raiz do projeto e, dentro dela, um ficheiro chamado «contentful.js».
require('dotenv').config();
const contentful = require('contentful');
const client = contentful.createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});
module.exports = { client };

É basicamente isso que este ficheiro faz: só configura a ligação uma vez, para que eu possa importá-lo sempre que precisar de extrair dados.
Criar a interface do blogue
É aqui que vou criar o servidor propriamente dito: ele liga-se ao Contentful, recupera as publicações do blogue e passa-as para um modelo de página para que sejam apresentadas.
Vou criar um ficheiro chamado server.js na raiz do meu projeto e colar isto lá dentro:
const express = require('express');
const path = require('path');
const { client } = require('./lib/contentful');
const { documentToHtmlString } = require('@contentful/rich-text-html-renderer');
const app = express();
const PORT = process.env.PORT || 3000;
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', async (req, res) => {
try {
const response = await client.getEntries({ content_type: 'pageBlogPost' });
const posts = response.items.map((post) => ({
title: post.fields.title,
contentHtml: post.fields.content
? documentToHtmlString(post.fields.content)
: null,
}));
res.render('index', { posts });
} catch (err) {
console.error(err);
res.status(500).send('Something went wrong fetching posts.');
}
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Este ficheiro liga-se ao Contentful, recupera todas as publicações com o ID do tipo de conteúdo «pageBlogPost» (que se encontra da mesma forma que antes, no modelo «Content», abrindo a página «Blog post» e copiando o ID) e envia esses dados para um modelo chamado «index» para os converter em HTML. Esse modelo ainda não existe, por isso vou criá-lo a seguir.
Vou criar uma pasta chamada «views» na raiz do meu projeto e, dentro dela, um ficheiro chamado «index.ejs». Vou colar isto lá dentro:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Headless CMS Blog</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<main>
<h1>My Headless CMS Blog</h1>
<div class="posts">
<% posts.forEach(post => { %>
<article class="post-card">
<h2><%= post.title %></h2>
<% if (post.contentHtml) { %>
<div class="post-content"><%- post.contentHtml %></div>
<% } %>
</article>
<% }) %>
</div>
</main>
</body>
</html>

Esta é a página que o navegador mostra. Ela percorre todas as publicações que o `server.js` envia, exibindo o título e, se houver, o conteúdo logo abaixo.
Vou criar mais uma pasta chamada «public» e, dentro dela, um ficheiro chamado «style.css». Vou colar isto lá dentro:
body {
font-family: sans-serif;
cor de fundo: #f9fafb;
margin: 0;
padding: 40px 20px;
}
main {
max-width: 700px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 30px;
}
.post-card {
fundo: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.post-card h2 {
margin-top: 0;
}

É o estilo mínimo necessário para que a página não pareça apenas texto simples e sem formatação quando a carregar no navegador.
A testar o que criámos
Está na hora de ver se isto funciona mesmo. Vou adicionar um script de arranque ao ` package.json ` para não ter de escrever o comando completo do `node` todas as vezes:
"scripts": {
"start": "node server.js"
}

Depois, de volta ao Prompt de Comando:
npm start
E vou abrir o http://localhost:3000 no navegador para ver o que acontece.
E aí estão elas, as mesmas publicações de exemplo do modelo do Contentful, a aparecerem mesmo na página.

Isto confirma que a ligação está a funcionar. O Contentful devolveu os dados da publicação e o servidor Express transformou-os em HTML na página.
Passo 4: Enviar o projeto para o GitHub
Antes de fazer a implementação em qualquer lugar, quero que isto seja enviado para o GitHub primeiro.
Vou criar um novo repositório aí.
Depois, de volta ao Prompt de Comando, vou executar estes comandos um a um:
git init git add . git commit -m "First commit" git branch -M main git remote add origin https://github.com/abdulrehman293/nodejs-headless-cms git push -u origin main
Vou voltar ao repositório e atualizar a página, e sim, está tudo lá, tirando o ficheiro .env e o node_modules, que é exatamente como deve ser.

Passo 5: Ligar o Cloudways ao GitHub
Neste momento, o meu projeto está a funcionar na configuração local e também já foi enviado para o GitHub. Agora vou transferi-lo do ambiente local para um servidor ativo. Para isso, vou usar a hospedagem gerida do Node.js da Cloudways, criada especificamente para implementar projetos como este diretamente a partir de um repositório Git.
No painel de controlo, vou clicar em «Node.js » no menu do lado esquerdo e, depois, clico em «Lançar agora».

A partir daí, vou escolher um plano. Este projeto não requer grande potência, por isso o plano Starter dá perfeitamente conta do recado.

Isso leva-me ao ecrã «Deploy Your Node.js Web App ». Vou clicar em «Connect Via Git», iniciar sessão no GitHub quando me for pedido e, assim que o Cloudways Deploy estiver autorizado, vou escolher o meu repositório «nextjs-headless-cms» da lista e continuar.

Passo 6: Implementar a aplicação e colocá-la em funcionamento
Nesta próxima parte é que eu explico à Cloudways em que consiste este projeto e como o executar.
Vou definir a «Predefinição do Framework» para «Express», já que é exatamente isso que este backend é. Quanto à «Versão do Node», o Node 24 (LTS) é a escolha certa aqui, pois é a linha atual com suporte a longo prazo. O «Diretório Raiz» fica com a configuração predefinida.

A seguir, vou clicar em «Alterar» em «Definições de compilação e saída» para expandir essa secção e, depois, definir o «Gestor de pacotes» como «npm», tal como usei no meu computador. Quanto ao «Ficheiro de entrada», é o «server.js», o mesmo ficheiro que dá início a tudo localmente também.

Agora, como o meu ficheiro .env nunca foi colocado no GitHub de propósito, preciso de voltar a adicionar essas chaves do Contentful manualmente aqui. Vou até às Variáveis de Ambiente, clico em «Adicionar» e insiro tanto o CONTENTFUL_SPACE_ID como o CONTENTFUL_ACCESS_TOKEN, com os mesmos valores do meu ficheiro local.


Também posso importar o ficheiro .env da pasta do meu projeto no meu computador, se não me apetecer colar as chaves manualmente.
Assim que tiver preenchido isso, vou clicar em «Implementar agora».
A partir daqui, o Cloudways pega no código diretamente do GitHub, instala as dependências e inicia a aplicação usando o ficheiro de entrada que eu indiquei. Não há nenhuma etapa de compilação, já que este projeto não precisa disso.

O momento da verdade
Assim que a implementação aparecer como bem-sucedida, vou aceder ao URL temporário do Cloudways que foi gerado.


E aí está. As mesmas publicações de exemplo do Contentful, agora a serem apresentadas em tempo real a partir do Cloudways, em vez de ficarem guardadas no meu portátil. O conteúdo está a percorrer todo o caminho, desde o Contentful, passando pelo meu servidor Express, até chegar a um URL público real que qualquer pessoa pode visitar.

Conclusão
Então, este foi o passo a passo completo para criar uma configuração de CMS headless com o Node.js. Expliquei porque é que o Node.js puro é uma escolha sólida para isto, falei das opções populares de CMS que existem, tanto as auto-hospedadas, como o Strapi, como as hospedadas, como o Contentful, e usei o Contentful para a implementação propriamente dita aqui.
Também passei por todo o processo de criar um pequeno backend em Express que recupera artigos de um CMS, os apresenta com o EJS, testei-o localmente e, depois, coloquei-o online no Cloudways.
Já publiquei o projeto finalizado no meu GitHub, por isso podes cloná-lo e reutilizar o código à vontade. E se quiseres implementar algo semelhante por conta própria, o nosso Serviço de Alojamento Gerido para Node.js trata exatamente deste fluxo de trabalho: liga o teu repositório, escolhe a configuração pré-definida do teu framework e já estás no ar.
P. O Node.js é um CMS?
Não. O Node.js é apenas um ambiente de execução do JavaScript, não um sistema de gestão de conteúdos por si só. Dito isto, algumas plataformas populares de CMS headless, como o Strapi, o KeystoneJS e o Payload, são, na verdade, desenvolvidas com o Node.js. Outras, como o Contentful e o Sanity, estão alojadas separadamente e são simplesmente utilizadas por uma aplicação Node.js através de uma API.
P. Qual é o melhor CMS headless para o Node.js?
Depende do que procuras. Se quiseres fazer a tua própria hospedagem e ser dono de tudo do início ao fim, o Strapi é uma ótima escolha, e é desenvolvido com o próprio Node.js. Se preferires evitar a hospedagem de um CMS e apenas obter conteúdo através de uma API, o Contentful ou o Sanity levam-te lá mais depressa.
P. Um CMS sem interface ajuda no SEO?
Sim, é possível. O CMS armazena o teu conteúdo, e a forma como esse conteúdo é renderizado no servidor determina a facilidade com que pode ser rastreado. O HTML renderizado no servidor, como o que este projeto cria com o Express e o EJS, é geralmente fácil de ler pelos motores de busca.
P. Tenho de usar o Express com o Node.js para isto?
Não, o Express é apenas uma das opções mais comuns para criar um backend em Node.js. Podes usar o Fastify, o Koa ou até mesmo o módulo « http » integrado no Node; a ideia principal de ir buscar dados de um CMS sem interface gráfica e apresentar o resultado mantém-se a mesma, seja qual for a opção escolhida.
Start Growing with Cloudways Today.
Our Clients Love us because we never compromise on these
Abdul Rehman
O Abdul é um profissional de marketing experiente em tecnologia, movido a café e criativo, que adora manter-se a par das últimas actualizações de software e gadgets tecnológicos. É também um escritor técnico competente que consegue explicar conceitos complexos de forma simples para um público alargado. Abdul gosta de partilhar os seus conhecimentos sobre a indústria da nuvem através de manuais de utilizador, documentação e publicações em blogues.