Como criar um blog com Next.js 15 em um fim de semana

Introdução
O Next.js 15 tinha acabado de ser lançado. Eu já havia lido a documentação oficial várias vezes e assistido a muitos tutoriais, mas ainda sentia que tudo ficava na teoria: entendia os conceitos de Server Actions e App Router, porém não sabia como aplicá-los em um projeto real. No fim de semana, resolvi parar de consumir tutoriais e construir algo de verdade: um blog full stack. O projeto envolveu frontend, backend, banco de dados e implantação. Dois dias depois, o blog estava no ar na Vercel, com 96 pontos de desempenho no Lighthouse.
Este texto conta todo o processo. Não é um tutorial que termina depois de copiar e colar código; a ideia é entender por que cada decisão foi tomada e quais armadilhas apareceram. A stack é Next.js 15 + Server Actions + Prisma + PostgreSQL, com código pensado para produção.
Por que escolhi o Next.js 15?
Demorei bastante para decidir a stack.
Quando o Next.js 15 foi lançado, vi gente na comunidade reclamando que havia mais uma atualização e que já não dava para acompanhar. Para ser sincero, também resisti um pouco, porque ainda não dominava completamente a versão 14. Depois de analisar os novos recursos com calma, percebi que a atualização valia a pena.
Server Actions: menos burocracia que API Routes
Ao trabalhar com desenvolvimento full stack, uma das partes mais cansativas era escrever API Routes. Era preciso criar api/posts/route.ts, definir o método POST, tratar o corpo da requisição, devolver a resposta… O mesmo processo se repetia toda vez.
Server Actions mudaram completamente essa dinâmica. Basta adicionar 'use server' antes da função e chamá-la diretamente no componente. Quando vi o recurso pela primeira vez, pensei: “Então agora o código do backend fica no frontend?”. Depois de experimentar, entendi a vantagem.
Antes, para criar um post, eu escrevia algo assim:
// Método antigo: exige a criação de uma API Route
// app/api/posts/route.ts
export async function POST(request: Request) {
const body = await request.json()
// Lógica de processamento...
}
// O frontend ainda precisa chamar fetch
const response = await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(data)
})
Agora, basta fazer isto:
// app/actions/post-actions.ts
'use server'
export async function createPost(formData: FormData) {
const title = formData.get('title')
const content = formData.get('content')
// Acesso direto ao banco de dados
return await prisma.post.create({
data: { title, content }
})
}
A chamada no componente é tão simples quanto chamar uma função local. Usando uma comparação cotidiana: antes você precisava ir buscar a comida no restaurante (API Routes); agora ela chega diretamente à sua casa (Server Actions).
Turbopack tornou o desenvolvimento mais de duas vezes mais rápido
No Next.js 15, o Turbopack deixou de ser experimental e passou a ser estável. Segundo os dados oficiais, o servidor local inicia 76,7% mais rápido e as atualizações de código ficam 96,3% mais rápidas. No começo, achei que fossem números de marketing, mas a experiência prática confirmou a diferença.
Meu projeto tem pouco mais de 30 componentes. Com Webpack, a inicialização levava 7–8 segundos; com Turbopack, caiu para menos de 2 segundos. Ao alterar o código, a atualização em tempo real é praticamente instantânea. Isso muda bastante a experiência de desenvolvimento.
Por que essa stack é adequada para um blog?
Escolhi Next.js para o blog principalmente por três motivos:
Vantagens nativas de SSR/SSG — SEO é essencial para um blog. A renderização no servidor e a geração estática do Next.js foram feitas para esse tipo de cenário. O crawler do Google recebe o HTML completo, uma vantagem enorme em relação ao React renderizado apenas no cliente.
Segurança de tipos do Prisma — Eu já usei Mongoose com MongoDB e precisava manter as definições de tipos manualmente; qualquer descuido podia introduzir bugs. O Prisma gera tipos TypeScript diretamente a partir do schema e oferece sugestões completas no editor, o que reduz bastante os erros.
Server Actions simplificam o desenvolvimento — Não é mais necessário escrever API Routes, e o volume de código cai pelo menos 30%. Se eu tivesse construído este blog da forma tradicional, provavelmente precisaria criar vários arquivos route.ts adicionais.
Escolha da stack e projeto da arquitetura
Depois de entender os motivos, era hora de definir como construir o projeto.
Minha stack completa
- Frontend: Next.js 15 + TypeScript + Tailwind CSS
- Backend: Next.js Server Actions + NextAuth.js
- Banco de dados: PostgreSQL + Prisma ORM
- Implantação: Vercel
Talvez você se pergunte por que não usei MongoDB. Eu também considerei essa opção no início, porque o MongoDB é realmente mais flexível. Depois percebi que o Prisma oferece um suporte melhor ao PostgreSQL e que um banco relacional é mais adequado para dados com relações claras, como posts, usuários e comentários.
Estrutura de diretórios
my-blog/
├── app/
│ ├── (auth)/ # Páginas relacionadas à autenticação
│ ├── blog/ # Páginas do blog
│ │ └── [slug]/ # Rota dinâmica
│ ├── dashboard/ # Painel de controle do usuário
│ ├── actions/ # Todas as Server Actions ficam aqui
│ └── api/auth/ # Configuração do NextAuth
├── components/ # Componentes reutilizáveis
├── lib/
│ ├── prisma.ts # Singleton do Prisma (muito importante!)
│ └── utils.ts # Funções utilitárias
├── prisma/
│ └── schema.prisma # Schema do banco de dados
└── public/ # Recursos estáticos
Revisei essa estrutura várias vezes até chegar à versão final. No começo, as Server Actions estavam espalhadas pelos arquivos de página. A manutenção ficou confusa, então criei um diretório actions exclusivo para organizá-las.
Projeto do schema do banco de dados
Cometi um erro grande nessa etapa. A primeira versão era complexa demais: incluí tags, categorias, estatísticas de leitura e várias outras coisas. Na metade da implementação, percebi que não precisava de tantas tabelas e gastei mais meio dia simplificando tudo.
O schema principal ficou assim:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
image String?
posts Post[]
createdAt DateTime @default(now())
}
model Post {
id String @id @default(cuid())
title String
slug String @unique
content String @db.Text
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([slug])
@@index([authorId])
}
Observe os dois @@index: eles são essenciais para o desempenho. A listagem do blog consulta posts com frequência pelo slug, enquanto o perfil do usuário filtra por authorId. Com esses índices, as consultas podem ficar várias vezes mais rápidas.
Implementação detalhada dos recursos principais
Com a arquitetura definida, chegou a parte mais interessante: escrever o código.
3.1 Configuração do ambiente e inicialização
Criar um projeto com Next.js 15 é bem simples:
npx create-next-app@latest my-blog
cd my-blog
npm install prisma @prisma/client zod next-auth
Depois de instalar o Prisma, inicialize-o:
npx prisma init
O comando gera prisma/schema.prisma e o arquivo .env. Configure a conexão com o PostgreSQL no .env:
DATABASE_URL="postgresql://username:password@localhost:5432/myblog?schema=public"
No desenvolvimento local, executei o PostgreSQL com Docker usando um único comando:
docker run --name blog-postgres -e POSTGRES_PASSWORD=mypassword -p 5432:5432 -d postgres
3.2 Integração do Prisma com o banco de dados
Depois de configurar o schema, execute a migration:
npx prisma migrate dev --name init
Há uma armadilha importante aqui: o padrão singleton do Prisma Client. Na primeira vez em que implantei na Vercel, esqueci completamente dessa configuração. Depois de meio dia, o site começou a exibir o erro “Too many connections”, e eu cheguei a pensar que estava sofrendo um ataque DDoS.
O ambiente de desenvolvimento do Next.js faz recarregamento em tempo real e cria uma nova instância do Prisma Client a cada recarga. O pool de conexões se esgota rapidamente. A configuração correta é esta:
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}
O código parece um pouco complicado, mas garante uma única instância do Prisma no ambiente de desenvolvimento, sem afetar a produção. Vale lembrar: essa é a prática recomendada oficialmente pelo Prisma.
3.3 Server Actions na prática
Criar posts é o recurso central do sistema. Veja como escrever a Server Action:
// app/actions/post-actions.ts
'use server'
import { prisma } from '@/lib/prisma'
import { revalidatePath } from 'next/cache'
import { z } from 'zod'
// Validação de dados com Zod e segurança de tipos
const PostSchema = z.object({
title: z.string().min(1, 'O título é obrigatório').max(100),
content: z.string().min(10, 'O conteúdo deve ter pelo menos 10 caracteres'),
slug: z.string().regex(/^[a-z0-9-]+$/, 'O slug deve conter apenas letras minúsculas, números e hífens')
})
export async function createPost(formData: FormData) {
// Validação dos dados
const validatedFields = PostSchema.safeParse({
title: formData.get('title'),
content: formData.get('content'),
slug: formData.get('slug')
})
if (!validatedFields.success) {
return { error: 'Falha na validação dos dados' }
}
try {
const post = await prisma.post.create({
data: {
...validatedFields.data,
authorId: 'user-id-here' // Em um projeto real, obtenha o valor da session
}
})
// Revalida o cache para exibir o novo post imediatamente
revalidatePath('/blog')
return { success: true, post }
} catch (error) {
return { error: 'Falha ao criar o post' }
}
}
Use-a diretamente no componente:
// app/dashboard/new-post/page.tsx
import { createPost } from '@/app/actions/post-actions'
export default function NewPost() {
return (
<form action={createPost}>
<input name="title" placeholder="Título" />
<textarea name="content" placeholder="Conteúdo" />
<input name="slug" placeholder="Slug da URL" />
<button type="submit">Publicar</button>
</form>
)
}
Percebeu? Não é necessário usar useState, fetch ou tratar o evento onSubmit. O formulário chama a Server Action diretamente, e o Next.js cuida da serialização, da requisição de rede e do tratamento de erros.
No início, eu também não entendia bem a diferença entre Server Actions e API Routes. Depois ficou claro: Server Actions são como pedir comida e recebê-la em casa; API Routes são como ir buscá-la no restaurante. A primeira opção é prática, enquanto a segunda oferece mais flexibilidade. Na maioria dos casos, Server Actions são suficientes.
3.4 Sistema de autenticação de usuários
Usei NextAuth.js para a autenticação, e a configuração é relativamente simples:
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GitHubProvider from 'next-auth/providers/github'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { prisma } from '@/lib/prisma'
export const authOptions = {
adapter: PrismaAdapter(prisma),
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!
})
]
}
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }
Para configurar o GitHub OAuth, crie um aplicativo no GitHub Developer Settings e adicione o Client ID e o Secret ao .env. Todo o processo levou 10 minutos, muito menos trabalho do que implementar autenticação JWT por conta própria.
3.5 Estratégia de otimização com SSR/SSG
Essa parte é essencial para o desempenho. Para ser sincero, no início usei SSR (renderização no servidor) em tudo. Depois percebi que consultar o banco a cada acesso à listagem do blog era desnecessário e adotei uma estratégia híbrida.
Listagem do blog — SSG + ISR:
// app/blog/page.tsx
import { prisma } from '@/lib/prisma'
// Regenera uma vez por hora
export const revalidate = 3600
export default async function BlogList() {
const posts = await prisma.post.findMany({
where: { published: true },
orderBy: { createdAt: 'desc' }
})
return (
<div>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.content.slice(0, 150)}...</p>
</article>
))}
</div>
)
}
A página gera HTML estático durante o build e é regenerada automaticamente a cada hora. Quando alguém a acessa, recebe diretamente o arquivo estático, o que torna o carregamento muito rápido.
Página do post — SSR dinâmico:
// app/blog/[slug]/page.tsx
export default async function Post({ params }: { params: { slug: string } }) {
const post = await prisma.post.findUnique({
where: { slug: params.slug }
})
if (!post) notFound()
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
)
}
Essa página consulta o banco a cada acesso para obter o conteúdo mais recente, uma estratégia adequada para posts atualizados com frequência.
Comparação de desempenho:
A diferença é evidente. É por isso que o Next.js funciona tão bem para blogs: oferece bom SEO e desempenho.
Implantação e otimização
Com o código pronto, chegou a hora mais esperada: colocar o projeto no ar.
Processo de implantação na Vercel
Depois de enviar o código para o GitHub, importei o repositório diretamente na Vercel. A plataforma detectou um projeto Next.js e configurou tudo automaticamente. As únicas definições manuais foram as variáveis de ambiente:
DATABASE_URL="conexão do banco de dados de produção"
GITHUB_ID="OAuth Client ID"
GITHUB_SECRET="OAuth Secret"
NEXTAUTH_URL="https://your-domain.vercel.app"
NEXTAUTH_SECRET="string aleatória"
Para o banco de produção, usei o PostgreSQL gratuito do Supabase, que oferece 500 MB por mês, o suficiente para um blog pessoal.
Depois de clicar em Deploy, o site entrou no ar em cerca de 2 minutos. Na primeira vez em que vi meu domínio funcionando, fiquei alguns segundos olhando para a tela e depois tirei uma captura para compartilhar com os amigos.
Otimizações para produção
A implantação não encerra o trabalho. Ainda há alguns ajustes importantes:
Configuração do pool de conexões do Prisma:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
// Obrigatório no ambiente serverless da Vercel
directUrl = env("DIRECT_URL")
}
Em um ambiente serverless, cada chamada de função pode criar uma nova conexão. Configurar directUrl permite reutilizar o pool.
Otimização de imagens:
import Image from 'next/image'
<Image
src="/avatar.jpg"
alt="Avatar do usuário"
width={100}
height={100}
// O Next.js faz a compactação e a otimização automaticamente
/>
O componente Image do Next.js converte as imagens automaticamente para WebP e faz carregamento sob demanda, com uma melhora perceptível no desempenho.
Pontuação final de desempenho:
No Lighthouse, obtive 96 pontos no desktop, 92 no celular e 100 em SEO. Ver esse resultado foi muito gratificante: em dois dias, saí do zero e coloquei no ar um projeto com desempenho de produção.
Próximas extensões e recursos de aprendizagem
O blog ainda está na versão MVP e pode receber vários recursos:
- Editor Markdown: pode ser integrado com o react-md-editor
- Sistema de comentários: estou considerando o Giscus, baseado no GitHub Discussions
- Pesquisa: Algolia ou busca de texto completo com Prisma
- Modo escuro: fácil de implementar com next-themes
Meu próximo passo é adicionar um editor Markdown para facilitar a escrita dos posts.
Recursos de aprendizagem recomendados:
- Documentação oficial do Next.js — continua sendo a fonte mais confiável
- Documentação do Prisma — ler o Getting Started já oferece uma boa base
- Código completo deste projeto — você pode cloná-lo e executá-lo diretamente
Na prática, construir uma vez ensina mais do que ler a documentação dez vezes. A teoria é importante, mas é o projeto real que consolida o conhecimento.
Conclusão
Revendo este projeto de fim de semana, estes foram os principais aprendizados:
- A capacidade das Server Actions: elas realmente substituem a maioria das API Routes e aumentam bastante a produtividade
- A segurança de tipos do Prisma: o suporte completo a TypeScript dá muito mais confiança ao escrever código
- A flexibilidade de SSG/SSR: escolher a estratégia de renderização de acordo com o cenário permite equilibrar desempenho e SEO
- A simplicidade da implantação na Vercel: do código ao site no ar, o processo levou menos de 5 minutos
Para ser sincero, o maior ganho não foi a tecnologia em si, mas a confiança. Desenvolvimento full stack não é tão inacessível quanto parece; o principal é começar a construir.
Se você também quer criar seu próprio blog, comece agora. Encontrar problemas faz parte do processo: eu também consultei a documentação enquanto programava e precisei resolver muitas armadilhas antes de tudo funcionar. Quando você vê o projeto no ar, o esforço faz sentido.
Espero que este texto ajude você a evitar alguns desses obstáculos. Se tiver dúvidas, deixe um comentário; vou tentar responder.
Quero ver o seu projeto no ar.
Criar um blog pronto para produção com Next.js 15
Processo completo, da configuração do ambiente à implantação, com Server Actions, Prisma e otimizações de SSG/SSR
Estimated time: PT16H
-
1
Step 1: Configuração do ambiente e inicialização do projeto
Crie um projeto Next.js 15: -
2
Step 2: Configuração do schema do banco de dados com Prisma
Defina o schema principal: -
3
Step 3: Implementação dos recursos principais com Server Actions
Crie o arquivo de Server Actions: -
4
Step 4: Configuração do sistema de autenticação
Instale o NextAuth.js: -
5
Step 5: Otimização da estratégia de renderização com SSR/SSG
Use SSG + ISR na listagem do blog: em app/blog/page.tsx, defina export const revalidate = 3600 para regenerar a página a cada hora. Use prisma.post.findMany para consultar os posts publicados e ordene por createdAt em ordem decrescente. A página gera HTML estático durante o build e é regenerada automaticamente a cada hora. Quando alguém a acessa, recebe diretamente o arquivo estático, com carregamento de aproximadamente 200 ms. Use SSR dinâmico na página de cada post: em app/blog/[slug]/page.tsx, consulte o banco a cada acesso para obter o conteúdo mais recente. Use prisma.post.findUnique({ where: { slug: params.slug } }); essa estratégia é adequada para posts atualizados com frequência e leva cerca de 800 ms. Comparação de desempenho: páginas SSG ~200 ms, páginas SSR ~800 ms e CSR puro ~1.500 ms. A diferença é evidente. -
6
Step 6: Implantação na Vercel e otimização
Envie o código ao GitHub: faça push do projeto para um repositório do GitHub. Importe o projeto na Vercel: importe o repositório diretamente; ao detectar um projeto Next.js, a Vercel faz a configuração automaticamente. Configure as variáveis de ambiente: adicione DATABASE_URL (conexão do banco de produção), GITHUB_ID, GITHUB_SECRET, NEXTAUTH_URL (https://your-domain.vercel.app) e NEXTAUTH_SECRET (string aleatória) nas configurações do projeto. Para o banco de produção, recomendo o PostgreSQL gratuito do Supabase (500 MB por mês, suficiente para um blog pessoal). Configure o pool de conexões do Prisma: adicione directUrl = env(“DIRECT_URL”) ao datasource em prisma/schema.prisma. Em um ambiente serverless, cada chamada de função pode criar uma nova conexão; directUrl permite reutilizar o pool. Otimize as imagens: use o componente Image do Next.js, que converte automaticamente para WebP e faz carregamento sob demanda, com melhora perceptível no desempenho. Depois de clicar em Deploy, o site entra no ar em cerca de 2 minutos. Pontuação final no Lighthouse: 96 no desktop, 92 no celular e 100 em SEO.
FAQ
Qual é a diferença entre Server Actions e API Routes no Next.js 15? Quando usar cada opção?
Vantagens das Server Actions:
1) Reduzem o volume de código em 30%, sem precisar criar API Routes
2) Podem ser chamadas diretamente no componente, sem useState, fetch nem tratamento do evento onSubmit
3) O Next.js cuida automaticamente da serialização, das requisições de rede e dos erros
4) Oferecem segurança de tipos e permitem usar os tipos do TypeScript diretamente
Exemplo de uso: adicione 'use server' antes da função e chame-a diretamente no componente (<form action={createPost}>).
Vantagens das API Routes:
• São mais flexíveis e permitem tratar lógicas de requisição complexas
• Aceitam middleware
• São adequadas quando é necessário personalizar a resposta HTTP
Na maioria dos casos, Server Actions são suficientes. Use API Routes somente quando precisar de um tratamento HTTP mais complexo.
Quanto o Turbopack melhora o desempenho? Como é a experiência de uso na prática?
Dados oficiais:
• Inicialização do servidor local 76,7% mais rápida
• Atualização de código 96,3% mais rápida
Experiência prática:
• Meu projeto tem pouco mais de 30 componentes. Com Webpack, a inicialização levava 7–8 segundos; com Turbopack, caiu para menos de 2 segundos
• Ao alterar o código, a atualização em tempo real é praticamente instantânea
• A diferença na experiência de desenvolvimento é enorme
O Turbopack é escrito em Rust e é muito mais rápido que o Webpack, principalmente em projetos grandes. Se você ainda usa Webpack, vale a pena atualizar para o Next.js 15 e experimentar o Turbopack.
Por que o padrão singleton do Prisma Client é importante? O que acontece sem essa configuração?
Cenário do problema:
• O ambiente de desenvolvimento do Next.js faz recarregamento em tempo real e cria uma nova instância do Prisma Client a cada recarga
• O pool de conexões se esgota rapidamente e causa o erro "Too many connections"
• Na minha primeira implantação na Vercel, esqueci completamente dessa configuração. Depois de meio dia no ar, o site exibiu esse erro e cheguei a pensar que estava sofrendo um ataque DDoS
Configuração correta:
• Implemente um singleton global em lib/prisma.ts:
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma;
}
Esse código garante uma única instância do Prisma no ambiente de desenvolvimento, sem afetar a produção. Vale lembrar: essa é a prática recomendada oficialmente pelo Prisma.
Quais são as diferenças entre SSG, SSR e ISR? Como escolher?
• Gera HTML estático durante o build e oferece a maior velocidade (~200 ms)
• É adequado para páginas cujo conteúdo muda pouco, como a listagem do blog e a página Sobre
SSR (Server-Side Rendering):
• Gera o HTML no servidor a cada requisição
• É adequado para páginas que precisam de dados em tempo real, como detalhes de posts e perfis de usuários
• O tempo de carregamento é de aproximadamente 800 ms
ISR (Incremental Static Regeneration):
• Combina SSG com regeneração periódica, unindo a velocidade do SSG à flexibilidade do SSR
• É adequado para páginas atualizadas ocasionalmente, como uma listagem do blog regenerada a cada hora
CSR puro (Client-Side Rendering):
• Renderiza no navegador, oferece SEO ruim e leva cerca de 1.500 ms para carregar
• Não é recomendado para blogs
Estratégia de escolha:
• Use SSG + ISR na listagem do blog (export const revalidate = 3600)
• Use SSR dinâmico nas páginas de cada post
• Use SSG puro na página Sobre
Comparação de desempenho: SSG ~200 ms, SSR ~800 ms e CSR puro ~1.500 ms. A diferença é evidente.
Por que escolher PostgreSQL em vez de MongoDB? Como é o suporte do Prisma ao PostgreSQL?
1) O suporte do Prisma ao PostgreSQL é melhor, com segurança de tipos, ferramentas de migração e otimização de consultas bem desenvolvidas
2) Um banco relacional é mais adequado para dados com relações claras, como posts, usuários e comentários
3) O PostgreSQL tem recursos avançados de busca de texto completo, úteis para a pesquisa do blog
4) Oferece mais estabilidade em produção e suporte completo a transações
Vantagens do Prisma:
• Ele gera tipos TypeScript diretamente a partir do schema, oferecendo sugestões completas no editor e reduzindo bastante a chance de erros
• Eu já usei Mongoose com MongoDB e precisava manter as definições de tipos manualmente, o que facilitava a introdução de bugs
• A segurança de tipos do Prisma me dá muito mais confiança ao programar
Se você precisa lidar com dados relacionais complexos, PostgreSQL + Prisma é uma ótima combinação.
O que exige atenção ao implantar um projeto Next.js na Vercel? Como otimizar o ambiente de produção?
1) Envie o código para o GitHub
2) Importe o repositório do GitHub na Vercel; ao detectar um projeto Next.js, a plataforma faz a configuração automaticamente
3) Configure as variáveis de ambiente (DATABASE_URL, GITHUB_ID, GITHUB_SECRET, NEXTAUTH_URL e NEXTAUTH_SECRET)
4) Clique em Deploy; o site entra no ar em cerca de 2 minutos
Otimizações para produção:
1) Configuração do pool de conexões do Prisma:
• Adicione directUrl = env("DIRECT_URL") ao datasource em prisma/schema.prisma
• Em um ambiente serverless, cada chamada de função pode criar uma nova conexão; configurar directUrl permite reutilizar o pool
2) Otimização de imagens:
• Use o componente Image do Next.js, que converte automaticamente as imagens para WebP e faz carregamento sob demanda, com melhora perceptível no desempenho
3) Para o banco de produção, recomendo o PostgreSQL gratuito do Supabase (500 MB por mês, suficiente para um blog pessoal)
Pontuação final de desempenho:
• No Lighthouse, obtive 96 pontos no desktop, 92 no celular e 100 em SEO
• Ver esse resultado foi muito gratificante: em dois dias, saí do zero e coloquei no ar um projeto com desempenho de produção
15 min de leitura · Publicado em: 24 nov 2025 · Atualizado em: 4 set 2026
Guia completo Next.js
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Next.js App Router para iniciantes: conceitos e uso básico
Entenda o Next.js App Router desde o início: Server Components, Client Components, arquivos especiais, rotas dinâmicas e busca de dados com exemplos práticos.
Parte 1 de 26
Próximo
Guia prático para migrar do Pages Router para o App Router no Next.js: estratégia gradual e armadilhas
Aprenda a migrar do Pages Router para o App Router no Next.js do início ao fim, com uma estratégia gradual, soluções para 7 armadilhas comuns e experiências de projetos reais em produção para atualizar com segurança para o Next.js 14.
Parte 3 de 26



Comentários
Entre com GitHub para comentar