Next.js es el framework de React más popular para crear aplicaciones web modernas. Te permite desarrollar apps con SSR, SSG, API Routes y mucho más, todo en un solo framework.
Next.js extiende las capacidades del framework base, añadiendo funcionalidades como:
Next.js resuelve los problemas de SEO, performance y experiencia de usuario que tiene React vanilla. Es la opción ideal para apps de producción.
Acontinuacion se muestra como instalar Next.js usando create-next-app, el método más sencillo y recomendado.
# Con npm
npx create-next-app@latest mi-proyecto-nextjs
# Con yarn
yarn create next-app mi-proyecto-nextjs
# Con pnpm
pnpm create next-app mi-proyecto-nextjs Durante la instalación, Next.js te preguntará sobre TypeScript, ESLint, Tailwind CSS, App Router, etc. Para empezar, acepta las opciones por defecto.
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
} # Modo desarrollo (puerto 3000)
npm run dev
# Construir para producción
npm run build
# Ejecutar en producción
npm run start
# Linting del código
npm run lint mi-proyecto-nextjs/
├── app/ # App Router (Next.js 13+)
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── public/ # Archivos estáticos
├── next.config.js # Configuración de Next.js
├── package.json
└── tailwind.config.js # Si elegiste Tailwind Next.js 13+ usa App Router por defecto. Si necesitas Pages Router (sistema anterior), puedes crear una carpeta pages/ en la raíz del proyecto.
next.config.jsEste archivo es la configuración principal de Next.js. Asegúrate de incluirlo en la raíz de tu proyecto.
/** @type {import('next').NextConfig} */
const nextConfig = {
// Configuraciones básicas
reactStrictMode: true,
// Optimización de imágenes
images: {
domains: ['example.com'],
},
// Variables de entorno públicas
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
}
}
module.exports = nextConfig app/layout.tsxEl archivo layout.tsx define el layout principal de tu aplicación. Asegúrate de incluirlo en la carpeta app/ de tu proyecto.
import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: 'Mi App Next.js',
description: 'Aplicación creada con Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="es">
<body>
<header>
<nav>Mi Navegación</nav>
</header>
<main>{children}</main>
<footer>© 2024 Mi App</footer>
</body>
</html>
)
} app/page.tsxEl archivo page.tsx es la página principal de tu aplicación. Asegúrate de incluirlo en la carpeta app/ de tu proyecto.
export default function HomePage() {
return (
<div>
<h1>¡Bienvenido a Next.js!</h1>
<p>Esta es tu primera página con Next.js</p>
</div>
)
} package.jsonEl archivo package.json contiene las dependencias necesarias para tu proyecto. Asegúrate de incluirlo en la raíz de tu proyecto.
{
"name": "mi-proyecto-nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "15.0.0",
"typescript": "^5"
}
} En este escenario, consideremos una aplicación con autenticación y dashboard. La estructura recomendada para proyectos medianos/grandes es la siguiente:
mi-proyecto-nextjs/
├── app/ # App Router
│ ├── (auth)/ # Grupos de rutas
│ │ ├── login/
│ │ └── register/
│ ├── dashboard/ # Rutas anidadas
│ │ ├── settings/
│ │ └── profile/
│ ├── api/ # API Routes
│ │ ├── users/
│ │ └── posts/
│ ├── globals.css
│ ├── layout.tsx
│ ├── loading.tsx # UI de carga
│ ├── error.tsx # UI de error
│ ├── not-found.tsx # 404 personalizado
│ └── page.tsx
├── components/ # Componentes reutilizables
│ ├── ui/ # Componentes de UI básicos
│ └── forms/ # Componentes de formularios
├── lib/ # Utilidades y configuraciones
│ ├── auth.ts
│ ├── db.ts
│ └── utils.ts
├── public/ # Archivos estáticos
│ ├── images/
│ └── icons/
├── styles/ # Estilos globales
├── types/ # Definiciones de TypeScript
└── hooks/ # Custom hooks Estas convenciones ayudan a mantener una estructura organizada y consistente en tu proyecto.
| Archivo | Propósito | Ubicación |
|---|---|---|
layout.tsx | Layout compartido | Cualquier carpeta en app/ |
page.tsx | Página de ruta | Cualquier carpeta en app/ |
loading.tsx | UI de carga | Cualquier carpeta en app/ |
error.tsx | UI de error | Cualquier carpeta en app/ |
not-found.tsx | Página 404 | Cualquier carpeta en app/ |
Los paréntesis (auth) crean grupos de rutas que no afectan la URL. Útil para organizar rutas relacionadas sin cambiar la estructura de URLs.
La carpeta lib/ contiene código reutilizable, configuraciones y utilidades:
// lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('es-ES').format(date)
}
// lib/auth.ts
import { NextAuthOptions } from "next-auth"
export const authOptions: NextAuthOptions = {
providers: [
// Configuración de proveedores
],
callbacks: {
// Callbacks personalizados
}
}
// lib/db.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 La carpeta ui/ dentro de components/ contiene componentes básicos reutilizables:
// components/ui/button.tsx
import { cn } from "@/lib/utils"
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'default' | 'destructive' | 'outline'
size?: 'default' | 'sm' | 'lg'
}
export function Button({
className,
variant = 'default',
size = 'default',
...props
}: ButtonProps) {
return (
<button
className={cn(
"inline-flex items-center justify-center rounded-md font-medium",
{
'bg-blue-600 text-white hover:bg-blue-700': variant === 'default',
'bg-red-600 text-white hover:bg-red-700': variant === 'destructive',
'border border-gray-300 bg-white hover:bg-gray-50': variant === 'outline',
},
{
'h-10 px-4 py-2': size === 'default',
'h-9 px-3': size === 'sm',
'h-11 px-8': size === 'lg',
},
className
)}
{...props}
/>
)
}
// components/ui/input.tsx
import { cn } from "@/lib/utils"
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
export function Input({ className, type, ...props }: InputProps) {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-sm",
"placeholder:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500",
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
/>
)
} // app/contact/page.tsx
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export default function ContactPage() {
return (
<div className="max-w-md mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Contacto</h1>
<form className="space-y-4">
<Input
type="email"
placeholder="tu@email.com"
/>
<Input
type="text"
placeholder="Tu nombre"
/>
<Button type="submit" className="w-full">
Enviar mensaje
</Button>
</form>
</div>
)
} Separa componentes básicos (ui/) de componentes específicos del negocio. Esto facilita el mantenimiento y la reutilización del código.
| Carpeta | Contenido | Ejemplo |
|---|---|---|
app/ | Rutas y layouts | page.tsx, layout.tsx |
components/ui/ | Componentes básicos | Button, Input, Modal |
components/ | Componentes específicos | Header, ProductCard |
lib/ | Utilidades y config | utils.ts, auth.ts, db.ts |
hooks/ | Custom hooks | useAuth, useLocalStorage |
Con esta estructura tendrás un proyecto Next.js bien organizado, escalable y fácil de mantener.