E-commerce com Next.js
Como criar uma loja de e-commerce com Next.js para produção: catálogo, checkout, estoque e SEO
Crie uma loja Next.js 16 pronta para produção, com produtos, variantes, carrinhos, preços definidos pelo servidor, Stripe Checkout, estoque, SEO e implantação.
Uma vitrine se torna um sistema de comércio quando catálogo, preços, estoque, estado dos pagamentos, pedidos e processamento das entregas precisam permanecer consistentes sob requisições simultâneas.
Definir os limites entre as partes do sistema de comércio
Trail Supply é o exemplo usado ao longo do guia: uma loja de artigos para atividades ao ar livre que vende o Alpine Shell em várias cores e tamanhos. A vitrine apresenta o catálogo; a camada de comércio controla os preços oficiais, o estoque, os carrinhos, os pagamentos e os pedidos; provedores externos cuidam dos pagamentos e e-mails. Defina esses limites antes de escolher componentes.
Defina a fonte de verdade de cada valor. Um sistema de conteúdo pode cuidar das descrições editoriais, enquanto o banco de dados comercial controla SKU, preço e estoque. A página do produto pode combinar essas fontes, mas o checkout nunca deve confiar nos dados editoriais ou no estado do navegador para obter valores transacionais.
- —Catálogo: produtos, variantes, categorias, mídia e estado de publicação.
- —Comércio: preço, moeda, dados para cálculo de impostos, estoque, carrinhos, pedidos e reembolsos.
- —Identidade: token anônimo do carrinho, conta do cliente, endereços e permissões.
- —Operações: eventos de pagamento, tarefas de processamento de pedidos, e-mail, saúde, logs e versões.
Modelar produtos e variantes disponíveis para compra
Um produto descreve as características comuns do Alpine Shell. Uma variante representa uma combinação específica disponível para compra, como azul no tamanho médio, com SKU, referência de preço, estoque e status próprios. Use IDs estáveis por trás de slugs legíveis para que as URLs possam mudar sem comprometer pedidos ou a conciliação de eventos.
Diferencie o que pode ser publicado do que pode ser comprado. Um produto pode continuar visível mesmo com um tamanho indisponível; um item descontinuado pode continuar útil para suporte e busca com o checkout desativado. Use restrições no banco de dados para garantir SKUs únicos e vínculos de propriedade válidos, em vez de depender apenas da validação de formulários.
type Product = {
id: string;
slug: string;
name: string;
published: boolean;
};
type Variant = {
id: string;
productId: string;
sku: string;
color: string;
size: string;
priceId: string;
active: boolean;
};Renderizar as rotas do catálogo no servidor
Use Server Components para o conteúdo de categorias e produtos, de modo que as requisições diretas contenham títulos, descrições, preços, links de produtos e disponibilidade. Mantenha a galeria, o seletor de tamanho e o controle de adicionar ao carrinho em Client Components específicos. O cliente recebe uma visão limitada ao necessário para comprar, sem acesso irrestrito aos registros do banco.
Escolha a estratégia de cache conforme o ciclo de vida do conteúdo. Descrições e imagens podem mudar lentamente; preço e estoque exigem regras mais rigorosas. Coloque consultas estáveis do catálogo em cache com tags de produto e categoria e revalide-as após uma atualização aprovada. O checkout sempre recarrega os valores transacionais.
Tratar o carrinho como uma proposta
Um cliente anônimo pode receber um token aleatório de carrinho em um cookie HTTP-only, cujo registro no banco de dados guarda IDs de variantes e quantidades. Após o login, incorpore-o ao carrinho do cliente com regras explícitas para itens duplicados, variantes indisponíveis e limites de quantidade. Não armazene os preços oficiais em um cookie que possa ser alterado.
A página do carrinho pode exibir uma estimativa calculada, mas toda requisição de alteração ou checkout deve recarregar variantes, preços, limites de compra e estoque no servidor. Retorne correções por item quando um produto mudar, em vez de cobrar silenciosamente um valor diferente.
Concluir o pagamento de forma assíncrona
Crie a Stripe Checkout Session no servidor a partir do carrinho validado e inclua um ID estável do carrinho ou do pedido pendente nos metadados. A URL de retorno pode mostrar que o pagamento está sendo confirmado, mas não pode criar o pedido final sozinha.
Verifique a assinatura da Stripe sobre o corpo bruto do webhook, registre o ID do evento com uma restrição de unicidade e crie ou avance o pedido exatamente uma vez. Trate sessões concluídas e expiradas, falhas de pagamento, reembolsos e eventos repetidos. Coloque e-mail e processamento de pedidos na fila somente após haver um estado durável do pedido.
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: pricedCart.lines.map((line) => ({
price: line.stripePriceId,
quantity: line.quantity,
})),
success_url: SITE_URL + "/orders/confirm?session_id={CHECKOUT_SESSION_ID}",
cancel_url: SITE_URL + "/cart",
metadata: { pendingOrderId: pendingOrder.id },
});Manter o estoque transacional
Escolha quando o estoque será reservado: ao adicionar ao carrinho, criar o checkout ou confirmar o pagamento. Reservas no carrinho reduzem a disponibilidade aparente e exigem prazos de expiração curtos; reservar só no pagamento pode permitir mais checkouts simultâneos do que o estoque comporta. O modelo de processamento e entrega do produto determina esse equilíbrio.
Qualquer que seja a política escolhida, atualize o estoque de forma atômica e impeça quantidades negativas no banco de dados. Registre a expiração das reservas e concilie explicitamente eventos de pagamento atrasados. Os caches podem divulgar a disponibilidade, mas a tabela de estoque e a transação determinam se um pedido pode reservar unidades.
Facilitar a descoberta dos produtos e trabalhar o SEO
Defina deliberadamente um único modelo canônico para cada produto. Gere títulos, descrições, imagens Open Graph, JSON-LD Product e Offer, trilhas de navegação e entradas do sitemap a partir de registros publicados. Mantenha preço e disponibilidade consistentes com a página visível e o fluxo de checkout.
As páginas de categorias devem ter links reais para produtos importantes. Trate os filtros como estado da aplicação, a menos que uma combinação selecionada tenha demanda e conteúdo próprios. Para produtos descontinuados, escolha deliberadamente entre 200, redirecionamento, 404 ou 410, conforme a utilidade que a página ainda oferece aos clientes.
Implantar e testar o caminho da transação
A Adios executa o servidor de produção completo do Next.js como um processo persistente: Server Components, endpoints do carrinho, webhooks assinados e páginas de pedidos compartilham uma única versão. O manifesto declara a compilação, o comando de inicialização, a rota de saúde, a dependência do banco de dados e as referências a segredos junto do código-fonte.
Implante uma prévia e teste o HTML dos produtos, um carrinho adulterado, dois compradores simultâneos, o Checkout em modo de teste, eventos duplicados, uma sessão expirada, o encaminhamento de e-mail e um produto desconhecido. Inspecione os logs de compilação e execução e só promova a versão após a aplicação informar que está saudável. O domínio personalizado e o TLS gerenciado permanecem associados à versão verificada.
adios.yaml
name: trail-supply
build_cmd: npm ci && npm run build
start_cmd: npm start
runtime:
name: node@24
port: 3000
health_path: /api/health
requires:
- db
env:
DATABASE_URL: secret://DATABASE_URL
STRIPE_SECRET_KEY: secret://STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET: secret://STRIPE_WEBHOOK_SECRET