← Volver al Blog

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 Team10 min de lecturabeginner
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

10 min lectura

# 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

  • Sube a GitHub
  • 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

  • Conecta con Vercel
    • Ve a vercel.com
    • "Add New Project"
    • Importa tu repositorio
    • Click "Deploy"

    ¡Listo en ~30 segundos! 🚀

    ---

    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

  • Usa Server Components por defecto - Mejor rendimiento
  • Optimiza imágenes - Usa componente Image
  • Metadata en cada página - SEO
  • Loading states - Crea loading.js
  • Error boundaries - Crea error.js
  • ❌ DON'Ts

  • No uses 'use client' innecesariamente
  • No realices fetch en Client Components
  • No ignores el SEO
  • No uses , usa
  • ---

    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:

  • ✅ Añade más páginas
  • ✅ Integra una base de datos (Prisma + PostgreSQL)
  • ✅ Añade autenticación (NextAuth.js)
  • ✅ Crea un blog con MDX
  • ✅ Añade analytics (Vercel Analytics)
  • ---

    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 2026
    Share:

    Artículos Relacionados

    Read in English