Desenvolvimento Full-Stack Next.js com Cursor
O Next.js evoluiu para um framework full-stack React com App Router, Server Components e rotas de API integradas. Os recursos de IA do Cursor aceleram todos os aspectos do desenvolvimento Next.js, desde o scaffolding do projeto até o deploy na Vercel. Este guia aborda fluxos de trabalho práticos para construir aplicações Next.js de produção.

Configurando o Projeto com Cursor
Scaffolding de Novo Projeto
Comece pedindo ao Cursor para configurar um projeto Next.js moderno:
# Peça ao Cursor: "Gere o comando para criar um app Next.js 14+ com TypeScript e Tailwind"
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
Após a geração, deixe o Cursor configurar os arquivos essenciais:
// app/layout.tsx
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'My Next.js App',
description: 'Built with Cursor AI',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
Sempre especifique "App Router" ao pedir código Next.js ao Cursor. O Pages Router tem padrões diferentes e o Cursor pode padronizar para o estilo antigo.
Estrutura de Diretórios
Peça ao Cursor para gerar uma estrutura de pastas escalável:
my-app/
├── app/
│ ├── api/ # Rotas de API
│ ├── (auth)/ # Grupos de rotas (sem segmento de URL)
│ ├── dashboard/ # Páginas do dashboard
│ ├── layout.tsx # Layout raiz
│ ├── page.tsx # Página inicial
│ ├── loading.tsx # UI de loading
│ └── error.tsx # Error boundary
├── components/
│ ├── ui/ # Componentes UI reutilizáveis
│ └── forms/ # Componentes de formulário
├── lib/
│ ├── db.ts # Conexão com banco de dados
│ ├── auth.ts # Helpers de autenticação
│ └── utils.ts # Funções utilitárias
├── types/
│ └── index.ts # Tipos TypeScript globais
├── hooks/
│ └── useUser.ts # React hooks customizados
└── public/
└── images/ # Assets estáticos
Padrões do App Router
Server Components
O App Router usa Server Components por padrão. Use o Cursor para gerar código eficiente do lado do servidor:
// app/users/page.tsx - Server Component
import { Suspense } from 'react';
import { UserList } from '@/components/UserList';
import { UserListSkeleton } from '@/components/UserListSkeleton';
// Executa no servidor
async function getUsers() {
const res = await fetch('https://api.example.com/users', {
next: { revalidate: 60 } // Revalida a cada 60 segundos
});
if (!res.ok) throw new Error('Failed to fetch users');
return res.json();
}
export default async function UsersPage() {
const usersPromise = getUsers();
return (
<main className="p-8">
<h1 className="text-2xl font-bold mb-4">Users</h1>
<Suspense fallback={<UserListSkeleton />}>
<UserList usersPromise={usersPromise} />
</Suspense>
</main>
);
}
Peça ao Cursor "create a Server Component that fetches data with proper error handling and loading states" para obter os melhores resultados.
Client Components
Quando precisar de interatividade, marque o componente com 'use client':
// components/SearchForm.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
export function SearchForm() {
const [query, setQuery] = useState('');
const router = useRouter();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
router.push(`/search?q=${encodeURIComponent(query)}`);
};
return (
<form onSubmit={handleSubmit} className="flex gap-2">
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
className="border rounded px-3 py-2"
/>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
Search
</button>
</form>
);
}
Grupos de Rotas e Layouts
Use grupos de rotas para organizar páginas relacionadas sem afetar a URL:
app/
├── (marketing)/
│ ├── layout.tsx # Layout de marketing (nav/footer diferente)
│ ├── page.tsx # / (homepage)
│ ├── about/
│ │ └── page.tsx # /about
│ └── pricing/
│ └── page.tsx # /pricing
├── (dashboard)/
│ ├── layout.tsx # Layout de dashboard (sidebar, verificação de auth)
│ ├── dashboard/
│ │ └── page.tsx # /dashboard
│ └── settings/
│ └── page.tsx # /dashboard/settings
└── api/
└── ...
Rotas de API
Endpoints RESTful
Use o Cursor para criar rotas de API type-safe:
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
export async function GET() {
try {
const users = await db.user.findMany();
return NextResponse.json({ users });
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const validated = createUserSchema.parse(body);
const user = await db.user.create({
data: validated,
});
return NextResponse.json({ user }, { status: 201 });
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid input', details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 500 }
);
}
}
Handlers de Rotas Dinâmicas
// app/api/users/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const user = await db.user.findUnique({
where: { id: params.id },
});
if (!user) {
return NextResponse.json(
{ error: 'User not found' },
{ status: 404 }
);
}
return NextResponse.json({ user });
}
Autenticação
Implementando Auth com NextAuth.js
Peça ao Cursor para configurar a autenticação:
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { db } from '@/lib/db';
const handler = NextAuth({
adapter: PrismaAdapter(db),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
],
callbacks: {
session({ session, user }) {
if (session.user) {
session.user.id = user.id;
}
return session;
},
},
});
export { handler as GET, handler as POST };
Protegendo Rotas
// middleware.ts
import { withAuth } from 'next-auth/middleware';
export default withAuth({
pages: {
signIn: '/login',
},
});
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*'],
};
Integração com Banco de Dados
Configuração do Prisma
// lib/db.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const db = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = db;
Server Actions
Use Server Actions para submissions e mutations de formulários:
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
import { z } from 'zod';
const createPostSchema = z.object({
title: z.string().min(1),
content: z.string().min(1),
});
export async function createPost(formData: FormData) {
const data = Object.fromEntries(formData);
const validated = createPostSchema.parse(data);
const post = await db.post.create({
data: validated,
});
revalidatePath('/posts');
return { success: true, post };
}
// app/posts/new/page.tsx
import { createPost } from '@/app/actions';
export default function NewPostPage() {
return (
<form action={createPost}>
<input name="title" placeholder="Title" required />
<textarea name="content" placeholder="Content" required />
<button type="submit">Create Post</button>
</form>
);
}
Sempre valide entradas em Server Actions. Nunca confie em dados enviados pelo cliente.
Geração de Código com IA
Gerando Páginas
Descreva o que precisa e o Cursor gera a página completa:
Prompt: "Create a Next.js page at /products that displays a grid of product cards. Each card should show an image, name, price, and an 'Add to Cart' button. Use Server Components for data fetching and Tailwind for styling."
Gerando Rotas de API
Prompt: "Create a CRUD API for a Todo model with Prisma. Include GET all, GET by id, POST create, PATCH update, and DELETE endpoints. Add Zod validation and proper error handling."
Gerando Componentes
Prompt: "Generate a reusable DataTable component with sorting, filtering, and pagination. Use TypeScript and accept a generic row type."
Deploy na Vercel
Checklist Pré-Deploy
| Verificação | Comando |
|---|---|
| Checagem de tipos | npx tsc --noEmit |
| Lint | npm run lint |
| Build local | npm run build |
| Testes | npm test |
Variáveis de Ambiente
Configure variáveis de ambiente de produção na Vercel:
# .env.local (desenvolvimento)
DATABASE_URL="postgresql://..."
NEXTAUTH_SECRET="your-secret"
NEXTAUTH_URL="http://localhost:3000"
GOOGLE_CLIENT_ID="..."
GOOGLE_CLIENT_SECRET="..."
Configuração de Deploy
// vercel.json
{
"buildCommand": "prisma generate && next build",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"]
}
Peça ao Cursor "generate a complete guide for deploying this Next.js app to Vercel, including environment setup" para obter instruções específicas do projeto.
Otimização de Performance
Otimização de Imagens
import Image from 'next/image';
// Otimização automática
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
className="rounded-lg"
/>
Streaming e Suspense
import { Suspense } from 'react';
import { ProductList } from '@/components/ProductList';
import { ProductListSkeleton } from '@/components/ProductListSkeleton';
export default function ShopPage() {
return (
<div>
<h1>Shop</h1>
{/* Renderiza imediatamente */}
<CategoryNav />
{/* Faz streaming quando pronto */}
<Suspense fallback={<ProductListSkeleton />}>
<ProductList />
</Suspense>
</div>
);
}
Estratégias de Cache
| Estratégia | Caso de Uso | Implementação |
|---|---|---|
| Estático | Conteúdo que não muda | export const dynamic = 'force-static' |
| Revalidado | Conteúdo semi-estático | next: { revalidate: 60 } |
| Dinâmico | Conteúdo por usuário | export const dynamic = 'force-dynamic' |
| On-demand | Conteúdo que muda por evento | revalidatePath() / revalidateTag() |
Resumo
Construir aplicações full-stack Next.js com Cursor envolve:
- Scaffolding de projetos com padrões modernos usando IA
- Aproveitar Server Components para fetching de dados eficiente
- Criar rotas de API e Server Actions type-safe
- Implementar autenticação com NextAuth.js
- Fazer deploy na Vercel com configuração adequada
- Otimizar performance com streaming, Suspense e cache
O entendimento do Cursor sobre as convenções do Next.js significa que você pode descrever recursos em linguagem natural e receber código pronto para produção que segue as melhores práticas do framework.
Última atualização: Julho de 2025. Os recursos do Next.js variam conforme a versão instalada. O App Router requer Next.js 13+.