Volver a Next.js Básico

Metadata, Imágenes y Despliegue

Metadata Estática y Dinámica

// app/page.tsx — metadata estática import type { Metadata } from 'next'; export const metadata: Metadata = { title: 'Inicio | Mi App', description: 'Bienvenido a mi aplicación Next.js', openGraph: { title: 'Mi App', description: 'La mejor app', images: [{ url: '/og-imagen.png' }], }, }; export default function PaginaInicio() { return <h1>¡Bienvenido!</h1>; }
// app/blog/[slug]/page.tsx — metadata dinámica export async function generateMetadata({ params }: Props): Promise<Metadata> { const { slug } = await params; const post = await obtenerPost(slug); return { title: `${post.titulo} | Blog`, description: post.extracto, openGraph: { images: [post.imagenPortada], }, }; }

Imágenes Optimizadas

import Image from 'next/image'; // Optimizada: convierte a WebP, redimensiona, carga diferida function Avatar({ src, nombre }: { src: string; nombre: string }) { return ( <Image src={src} alt={nombre} width={64} height={64} className="rounded-full" /> ); } // Llenar contenedor padre function BannerHero() { return ( <div className="relative h-96"> <Image src="/hero.jpg" alt="Hero" fill className="object-cover" priority // Precarga — usar para imágenes visibles sin scroll /> </div> ); }

Variables de Entorno

# .env.local (nunca subir a git) DATABASE_URL="postgresql://user:pass@localhost:5432/midb" NEXT_PUBLIC_API_URL="https://api.example.com" # Expuesta al navegador
// Solo en servidor (sin prefijo NEXT_PUBLIC_) const db = new PrismaClient({ datasources: { db: { url: process.env.DATABASE_URL } }, }); // Disponible en el navegador const apiUrl = process.env.NEXT_PUBLIC_API_URL;

Despliegue

Vercel (Recomendado)

npm install -g vercel vercel # desplegar en preview vercel --prod # desplegar en producción

O conecta tu repo de GitHub a Vercel y cada push despliega automáticamente.

Docker

FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/public ./public EXPOSE 3000 CMD ["node", "server.js"]
// next.config.ts const nextConfig = { output: 'standalone', // Requerido para Docker }; export default nextConfig;

next.config.ts Esencial

import type { NextConfig } from 'next'; const nextConfig: NextConfig = { // Permitir imágenes de dominios externos images: { remotePatterns: [ { protocol: 'https', hostname: 'cdn.example.com' }, ], }, // Redirigir URLs antiguas async redirects() { return [ { source: '/ruta-vieja', destination: '/ruta-nueva', permanent: true }, ]; }, }; export default nextConfig;