Crear Tu Primer Proyecto con Next.js: Tutorial Completo
Tutorial paso a paso para crear tu primera aplicación Next.js desde cero. Aprende routing, componentes, SSR y deploy en Vercel. Perfecto para principiantes.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# Crear Tu Primer Proyecto con Next.js: Tutorial Completo
Next.js es el framework más popular para React en producción. En esta guía crearemos una aplicación completa Next.js paso a paso, desde la instalación hasta el deploy.
---
¿Qué Vamos a Construir?
Un portfolio personal con:
✅ Página de inicio
✅ Página sobre mí
✅ Blog con posts dinámicos
✅ Formulario de contacto
✅ Deployment en Vercel
---
Requisitos Previos
Conocimientos
- HTML, CSS básico
- JavaScript ES6
- React básico (componentes, JSX)
Software
# Node.js 18 o superior
node --version
# npm o pnpm
npm --version
---
Paso 1: Crear Proyecto Next.js
Instalación con create-next-app
npx create-next-app@latest mi-portfolio
Opciones Recomendadas
✔ Would you like to use TypeScript? → No (por ahora)
✔ Would you like to use ESLint? → Yes
✔ Would you like to use Tailwind CSS? → Yes
✔ Would you like to use src/ directory? → No
✔ Would you like to use App Router? → Yes
✔ Would you like to customize the default import alias? → No
Entrar al Proyecto
cd mi-portfolio
npm run dev
Abre http://localhost:3000 🎉
---
Paso 2: Estructura del Proyecto
mi-portfolio/
├── app/ ← Carpeta principal
│ ├── layout.js ← Layout compartido
│ ├── page.js ← Página de inicio
│ └── globals.css
├── public/ ← Imágenes, assets
├── next.config.js ← Configuración
└── package.json
Archivos Importantes
app/layout.js - Layout global (header, footer) app/page.js - Página de inicio (/)
app/globals.css - Estilos globales
---
Paso 3: Crear Página de Inicio
app/page.js
export default function Home() {
return (
<main className="min-h-screen flex flex-col items-center justify-center p-8">
<h1 className="text-6xl font-bold mb-4">
Hola, soy <span className="text-blue-600">Tu Nombre</span>
</h1>
<p className="text-xl text-gray-600 mb-8">
Desarrollador Web Frontend
</p>
<div className="flex gap-4">
<a
href="/sobre-mi"
className="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700"
>
Sobre Mí
</a>
<a
href="/blog"
className="border-2 border-blue-600 text-blue-600 px-6 py-3 rounded-lg hover:bg-blue-50"
>
Ver Blog
</a>
</div>
</main>
);
}
---
Paso 4: Routing en Next.js
Next.js usa file-based routing (routing basado en archivos).
Ejemplo de Estructura
app/
├── page.js → /
├── sobre-mi/
│ └── page.js → /sobre-mi
├── blog/
│ ├── page.js → /blog
│ └── [slug]/
│ └── page.js → /blog/:slug
└── contacto/
└── page.js → /contacto
Crear Página "Sobre Mí"
mkdir app/sobre-mi
app/sobre-mi/page.js:
export default function SobreMi() {
return (
<div className="max-w-3xl mx-auto p-8">
<h1 className="text-4xl font-bold mb-6">Sobre Mí</h1>
<p className="text-lg text-gray-700 mb-4">
¡Hola! Soy un desarrollador web apasionado por crear
experiencias digitales increíbles.
</p>
<h2 className="text-2xl font-bold mt-8 mb-4">Habilidades</h2>
<ul className="list-disc pl-6 space-y-2">
<li>React & Next.js</li>
<li>JavaScript/TypeScript</li>
<li>Tailwind CSS</li>
<li>Node.js</li>
</ul>
</div>
);
}
---
Paso 5: Layout Compartido
app/layout.js
import Link from 'next/link';
import './globals.css';
export const metadata = {
title: 'Mi Portfolio',
description: 'Portfolio de Desarrollador Web',
};
export default function RootLayout({ children }) {
return (
<html lang="es">
<body>
<nav className="bg-white shadow-md">
<div className="max-w-6xl mx-auto px-4 py-4">
<div className="flex justify-between items-center">
<Link href="/" className="text-2xl font-bold">
MiPortfolio
</Link>
<div className="flex gap-6">
<Link href="/" className="hover:text-blue-600">
Inicio
</Link>
<Link href="/sobre-mi" className="hover:text-blue-600">
Sobre Mí
</Link>
<Link href="/blog" className="hover:text-blue-600">
Blog
</Link>
<Link href="/contacto" className="hover:text-blue-600">
Contacto
</Link>
</div>
</div>
</div>
</nav>
{children}
<footer className="bg-gray-100 mt-16">
<div className="max-w-6xl mx-auto px-4 py-8 text-center text-gray-600">
<p>© 2026 Mi Portfolio. Todos los derechos reservados.</p>
</div>
</footer>
</body>
</html>
);
}
---
Paso 6: Blog con Rutas Dinámicas
Crear Lista de Posts
app/blog/page.js:import Link from 'next/link';
const posts = [
{
slug: 'primer-post',
title: 'Mi Primer Post',
description: 'Este es mi primer post en el blog',
date: '2026-02-15'
},
{
slug: 'aprendiendo-nextjs',
title: 'Aprendiendo Next.js',
description: 'Mis primeros pasos con Next.js',
date: '2026-02-16'
}
];
export default function Blog() {
return (
<div className="max-w-4xl mx-auto p-8">
<h1 className="text-4xl font-bold mb-8">Blog</h1>
<div className="space-y-6">
{posts.map((post) => (
<article
key={post.slug}
className="border border-gray-200 rounded-lg p-6 hover:shadow-lg transition-shadow"
>
<Link href={/blog/${post.slug}}>
<h2 className="text-2xl font-bold mb-2 hover:text-blue-600">
{post.title}
</h2>
</Link>
<p className="text-gray-600 mb-2">{post.description}</p>
<time className="text-sm text-gray-500">{post.date}</time>
</article>
))}
</div>
</div>
);
}
Crear Página Dinámica del Post
mkdir -p app/blog/[slug]
app/blog/[slug]/page.js:
const postsData = {'primer-post': {
title: 'Mi Primer Post',
date: '2026-02-15',
content:
<p>Este es el contenido de mi primer post.</p>
<p>Estoy aprendiendo Next.js y es increíble.</p>
},
'aprendiendo-nextjs': {
title: 'Aprendiendo Next.js',
date: '2026-02-16',
content:
<p>Next.js hace que crear aplicaciones React sea muy fácil.</p>
<p>El routing basado en archivos es genial.</p>
}
};
export default function Post({ params }) {
const post = postsData[params.slug];
if (!post) {
return <div>Post no encontrado</div>;
}
return (
<article className="max-w-3xl mx-auto p-8">
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
<time className="text-gray-600 mb-8 block">{post.date}</time>
<div
className="prose lg:prose-xl"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
</article>
);
}
// Generar páginas estáticamente
export async function generateStaticParams() {
return Object.keys(postsData).map((slug) => ({
slug
}));
}
---
Paso 7: Componentes Reutilizables
Crear Componente Button
components/Button.jsx:export default function Button({ children, href, variant = 'primary' }) {
const baseClasses = 'px-6 py-3 rounded-lg font-medium transition-colors';
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50'
};
return (
<a
href={href}
className={${baseClasses} ${variants[variant]}}
>
{children}
</a>
);
}
Usar Componente
import Button from '@/components/Button';
<Button href="/contacto">Contactar</Button>
<Button href="/blog" variant="secondary">Ver Blog</Button>
---
Paso 8: Imágenes Optimizadas
Next.js optimiza imágenes automáticamente con el componente Image.
import Image from 'next/image';
export default function Home() {
return (
<div>
<Image
src="/profile.jpg"
alt="Mi foto"
width={200}
height={200}
className="rounded-full"
/>
</div>
);
}
Beneficios:
- Lazy loading automático
- Formatos modernos (WebP)
- Responsive images
---
Paso 9: Metadata y SEO
Por Página
// app/sobre-mi/page.js
export const metadata = {
title: 'Sobre Mí | Mi Portfolio',
description: 'Conoce más sobre mí y mis habilidades como desarrollador web'
};
export default function SobreMi() {
// ...
}
Dinámica
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const post = postsData[params.slug];
return {
title: ${post.title} | Mi Blog,
description: post.description
};
}
---
Paso 10: Deploy en Vercel
Preparar para Deploy
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/tu-usuario/mi-portfolio.git
git push -u origin main
- Ve a vercel.com
- "Add New Project"
- Importa tu repositorio
- Click "Deploy"
---
Funciones Avanzadas
Server Components (Por defecto)
// Este componente se renderiza en el servidor
async function Usuarios() {
const res = await fetch('https://api.example.com/usuarios');
const usuarios = await res.json();
return (
<ul>
{usuarios.map(u => <li key={u.id}>{u.nombre}</li>)}
</ul>
);
}
Client Components
'use client'; // <-- Necesario para usar hooks
import { useState } from 'react';
export default function Contador() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicks: {count}
</button>
);
}
API Routes
app/api/contacto/route.js:import { NextResponse } from 'next/server';
export async function POST(request) {
const data = await request.json();
// Procesar formulario de contacto
console.log(data);
return NextResponse.json({
mensaje: 'Mensaje recibido'
});
}
---
Personalización Adicional
Fuentes de Google
import { Inter, Roboto_Mono } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
const robotoMono = Roboto_Mono({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html lang="es" className={inter.className}>
<body>{children}</body>
</html>
);
}
Variables de Entorno
.env.local:NEXT_PUBLIC_API_URL=https://api.example.com
EMAIL_SERVER=smtp.gmail.com
Uso:
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
---
Mejores Prácticas
✅ DO's
Image❌ DON'Ts
---
Estructura Recomendada
mi-portfolio/
├── app/
│ ├── (home)/
│ │ └── page.js
│ ├── blog/
│ │ ├── page.js
│ │ └── [slug]/
│ │ └── page.js
│ ├── api/
│ │ └── contacto/
│ │ └── route.js
│ ├── layout.js
│ └── globals.css
├── components/
│ ├── Button.jsx
│ ├── Card.jsx
│ └── Navbar.jsx
├── lib/
│ └── utils.js
└── public/
└── images/
---
Recursos de Aprendizaje
Documentación
📚 Next.js Docs: nextjs.org/docs
Tutoriales
- Next.js Learn - Curso oficial interactivo
- Vercel Templates - Ejemplos listos para usar
- YouTube: Lee Robinson (Vercel VP)
---
Próximos Pasos
Ahora que tienes tu primera app Next.js:
---
Conclusión
Has creado tu primera aplicación Next.js con:
✅ Routing basado en archivos
✅ Componentes Server y Client
✅ SEO optimizado
✅ Imágenes optimizadas
✅ Deploy en Vercel
Next.js hace que crear aplicaciones React profesionales sea fácil y rápido.---
Recursos Relacionados
---
Última actualización: 15 de febrero de 2026Artículos Relacionados
¿Qué es React y Por Qué Deberías Aprenderlo en 2026?
Descubre qué es React, cómo funciona y por qué es la biblioteca de JavaScript más popular para desarrollo web. Guía completa para principiantes con ejemplos prácticos.
Next.js vs React: ¿Cuál Deberías Elegir en 2026?
Comparativa completa entre Next.js y React. Descubre las diferencias clave, ventajas de cada uno y cuándo usar Next.js o React para tu proyecto web.
Cómo Desplegar Tu Aplicación Web Gratis en 2026
Guía completa para desplegar aplicaciones web gratis usando Vercel, Netlify, Railway y más. Aprende a poner tu proyecto en producción en minutos.