Depois de procrastinar por algum tempo, finalmente coloquei meu blog no ar usando GitHub Pages. O processo foi mais simples do que eu imaginava, e o melhor: totalmente de graça.
E nada mais justo do que o primeiro post "de verdade" ser sobre como o próprio blog foi feito. É tipo aqueles filmes que falam sobre fazer filmes - uma inception meta que todo dev que cria blog acaba fazendo em algum momento.
Por que escolhi GitHub Pages
Eu poderia ter optado por um VPS tradicional ou algum serviço de hospedagem pago, mas para um blog pessoal que vai ter atualizações esporádicas, não fazia sentido. O GitHub Pages oferece hospedagem gratuita, deploy automático toda vez que você faz push no repositório, SSL já incluído (seu site fica no HTTPS sem configuração extra), e você ganha um domínio no formato seuusuario.github.io. Para começar, é perfeito.
A stack que escolhi
Decidi usar Next.js como framework, mesmo sendo desenvolvedor backend com pouca experiência em frontend. Na verdade, esse projeto foi uma desculpa perfeita para aprender Next.js na prática. O Next.js tem suporte excelente para geração de sites estáticos, que é exatamente o que o GitHub Pages precisa. Adicionei TypeScript para ter tipagem e evitar bugs bobos (vício de backend developer), Tailwind CSS para estilizar sem precisar escrever CSS puro (porque honestamente, CSS nunca foi meu forte), e MDX para escrever os posts - que é basicamente Markdown mas com a possibilidade de usar componentes React quando precisar.
Como não sou expert em frontend, usei o Claude AI para me ajudar com ajustes de layout, CSS e componentes React. Foi especialmente útil para entender as melhores práticas do Tailwind e para criar layouts responsivos sem precisar brigar com CSS puro.
Mais tarde, também integrei o Giscus para ter um sistema de comentários baseado no GitHub Discussions. Achei interessante porque os comentários ficam armazenados no próprio repositório.
Começando do zero (ou quase)
O primeiro passo é criar um repositório no GitHub com um nome específico: seuusuario.github.io. No meu caso ficou orlandobitencourt.github.io. Esse nome não é uma sugestão, é obrigatório - é assim que o GitHub identifica que você quer usar o Pages.
Eu não comecei completamente do zero. Encontrei um template Next.js que já tinha uma estrutura básica de blog configurada, o que economizou bastante tempo. Se você quiser começar do zero mesmo, pode usar npx create-next-app@latest, mas preparar tudo sozinho vai tomar mais tempo.
Configurando o Next.js para gerar arquivos estáticos
Aqui mora o segredo da coisa toda. O GitHub Pages só serve arquivos estáticos HTML, CSS e JavaScript. O Next.js normalmente roda como um servidor, mas ele tem um modo de exportação que gera tudo como arquivos estáticos.
No arquivo next.config.mjs, você precisa adicionar algumas configurações:
1const nextConfig = {
2 output: 'export',
3 images: {
4 unoptimized: true,
5 },
6 basePath: '',
7 trailingSlash: true,
8};
9
10export default nextConfig;O output: 'export' é o que faz a mágica acontecer - ele diz pro Next.js gerar HTML puro ao invés de rodar como servidor. O images.unoptimized é necessário porque o sistema de otimização de imagens do Next.js precisa de um servidor rodando, coisa que não temos no GitHub Pages. E o trailingSlash: true evita problemas com URLs que às vezes davam 404.
Organizando os posts
Criei uma pasta app/blog/posts/ onde coloco todos os arquivos MDX dos posts. Cada arquivo tem um frontmatter no topo com informações do post:
1---
2title: "Título do Post"
3publishedAt: "2025-11-15"
4description: "Descrição breve"
5thumbnail: "/thumbnails/post.jpg"
6---
7
8# Título do Post
9
10Conteúdo aqui...Esse formato é bem parecido com Jekyll e outros geradores de site estático, então se você já usou algum, vai se sentir em casa.
Estrutura do projeto
A organização das pastas ficou assim:

A estrutura usa o App Router do Next.js 14, onde cada pasta dentro de app/ vira uma rota automaticamente. O arquivo [slug]/page.tsx é uma rota dinâmica que carrega o post baseado no nome do arquivo MDX.
Como os posts funcionam
O Next.js lê todos os arquivos .mdx da pasta posts/ durante o build. Para cada arquivo, ele:
- Extrai os metadados do frontmatter (título, data, descrição, thumbnail)
- Converte o Markdown em HTML
- Gera uma página estática em
/blog/nome-do-post
Na listagem de posts (app/blog/page.tsx e app/page.tsx), o código varre a pasta posts/, pega os metadados de cada arquivo, e renderiza os cards com título, data e thumbnail. Quando você clica em um post, ele carrega a página individual que foi gerada estaticamente.
O legal do MDX é que você não está limitado a Markdown puro. Se precisar de algo mais interativo - um gráfico, um componente customizado, qualquer coisa React - você pode simplesmente importar e usar no meio do texto.
Personalizando o visual
Depois de ter a estrutura básica funcionando, passei um bom tempo ajustando o layout. Melhorei a exibição dos cards de posts na home, ajustei espaçamentos e tamanhos de fonte, adicionei as thumbnails. Também personalizei as informações da bio, coloquei uma foto de perfil decente, configurei um favicon, e ajustei o footer com as informações de copyright.
Uma coisa que percebi é que fazer esses ajustes finos faz muita diferença. O template dá uma base boa, mas são esses pequenos detalhes que fazem o site parecer seu de verdade.
Configurando o deploy automático
O deploy automático funciona através do GitHub Actions. Toda vez que você dá push na branch main, o workflow roda automaticamente e atualiza o site.
Você precisa criar um arquivo .github/workflows/nextjs.yml com essa configuração:
1name: Deploy Next.js to GitHub Pages
2
3on:
4 push:
5 branches: ["main"]
6 workflow_dispatch:
7
8permissions:
9 contents: read
10 pages: write
11 id-token: write
12
13concurrency:
14 group: "pages"
15 cancel-in-progress: false
16
17jobs:
18 build:
19 runs-on: ubuntu-latest
20 steps:
21 - uses: actions/checkout@v4
22
23 - name: Setup Node
24 uses: actions/setup-node@v4
25 with:
26 node-version: "20"
27
28 - name: Install dependencies
29 run: npm ci
30
31 - name: Build
32 run: npm run build
33
34 - name: Upload artifact
35 uses: actions/upload-pages-artifact@v3
36 with:
37 path: ./out
38
39 deploy:
40 environment:
41 name: github-pages
42 url: ${{ steps.deployment.outputs.page_url }}
43 runs-on: ubuntu-latest
44 needs: build
45 steps:
46 - name: Deploy to GitHub Pages
47 id: deployment
48 uses: actions/deploy-pages@v4Basicamente o workflow instala as dependências, roda o build do Next.js, pega a pasta out/ que foi gerada, e faz o deploy. Simples assim.
Ativando o GitHub Pages
No repositório, você precisa ir em Settings > Pages e em Source selecionar GitHub Actions. É só isso. Na primeira vez que você der push, o workflow vai rodar e seu site vai pro ar.

Adicionando comentários com Giscus
Depois que o básico estava funcionando, decidi adicionar um sistema de comentários. O Giscus usa o GitHub Discussions para armazenar os comentários, o que é interessante porque tudo fica no próprio repositório.
Habilitei o GitHub Discussions no repositório, instalei o app do Giscus, e configurei o componente. Tive que fazer alguns ajustes de estilo para ficar consistente com o tema do site, mas no geral foi bem tranquilo.
Usando pnpm como gerenciador de pacotes
Uma escolha que fiz foi usar pnpm ao invés de npm. O pnpm é mais rápido e economiza espaço em disco. Se você for usar também, precisa instalar com npm install -g pnpm e criar um arquivo pnpm-workspace.yaml na raiz do projeto. Também vai precisar ajustar o workflow do GitHub Actions para usar pnpm install ao invés de npm ci.
Problemas que enfrentei
A primeira coisa que quebrou foram as imagens - todas retornavam 404. Demorei um pouco para descobrir que faltava o images.unoptimized: true no config. Outro problema foram links que davam 404, resolvido com o trailingSlash: true.
Teve uma vez também que o build rodava perfeitamente local mas quebrava no GitHub Actions. Descobri que era porque eu não estava testando o build de produção localmente. Agora sempre rodo npm run build e depois npx serve out para testar antes de commitar.
Melhorias contínuas
O legal de ter tudo no Git é que você pode ir fazendo melhorias aos poucos. Depois do deploy inicial, fui refinando o layout, corrigindo textos, ajustando estilos. Cada commit é uma melhoria pequena, mas no fim faz diferença.
O resultado
No final das contas, o blog ficou no ar em https://orlandobitencourt.github.io. Zero custo de hospedagem, deploy automático, e controle total sobre o código. Para um blog pessoal, é exatamente o que eu precisava.
Se você quiser ver o código completo ou usar como referência, está tudo aberto no GitHub.
Referências
Se quiser se aprofundar ou consultar a documentação oficial:
