Comercio electrónico con Next.js
Cómo crear una tienda de comercio electrónico con Next.js para producción: catálogo, pago, inventario y SEO
Crea una tienda de producción con Next.js 16, productos, variantes, carritos, precios controlados por el servidor, Stripe Checkout, inventario, SEO y despliegue.
Una tienda se convierte en un sistema de comercio cuando los datos del catálogo, los precios, el inventario, el estado de pago, los pedidos y su preparación deben mantenerse coherentes ante solicitudes simultáneas.
Dibuja los límites del comercio
El ejemplo que seguimos es Trail Supply: una tienda de artículos de exterior que vende Alpine Shell en varios colores y tallas. La tienda muestra los datos del catálogo; la capa de comercio controla los precios de referencia, el inventario, los carritos, los pagos y los pedidos; los proveedores externos gestionan el pago y el correo electrónico. Define esos límites antes de elegir componentes.
Define la fuente de referencia de cada valor. Un sistema de contenidos puede controlar las descripciones editoriales y una base de datos de comercio, los SKU, precios e inventario. La página de producto puede combinarlos, pero el proceso de pago nunca debe confiar en el estado editorial ni en el navegador para los valores transaccionales.
- —Catálogo: productos, variantes, categorías, contenido multimedia y estado de publicación.
- —Comercio: precio, moneda, datos fiscales, inventario, carritos, pedidos y reembolsos.
- —Identidad: token de carrito anónimo, cuenta de cliente, direcciones y permisos.
- —Operaciones: eventos de pago, tareas de preparación de pedidos, correo electrónico, salud, registros y versiones.
Modela los productos y las variantes que se pueden comprar
Un producto describe el modelo común Alpine Shell. Una variante representa una combinación concreta que se puede comprar, como azul y talla mediana, con su propio SKU, referencia de precio, inventario y estado. Usa IDs estables detrás de slugs legibles para que las URLs puedan cambiar sin romper los pedidos ni la conciliación de eventos.
Distingue lo que se puede publicar de lo que se puede comprar. Un producto puede seguir visible aunque una talla no esté disponible; un artículo descatalogado puede seguir siendo útil para soporte y búsqueda con el pago deshabilitado. Aplica restricciones de base de datos para los SKU únicos y la propiedad válida, en lugar de depender solo de la validación de formularios.
type Product = {
id: string;
slug: string;
name: string;
published: boolean;
};
type Variant = {
id: string;
productId: string;
sku: string;
color: string;
size: string;
priceId: string;
active: boolean;
};Renderiza las rutas del catálogo en el servidor
Usa Server Components para el contenido de categorías y productos, de modo que las solicitudes directas contengan títulos, descripciones, precios, enlaces de productos y disponibilidad. Mantén la galería, el selector de talla y el control para añadir al carrito como Client Components específicos. El cliente recibe una vista limitada de lo que puede comprar, en lugar de registros de base de datos sin restricciones.
Elige la estrategia de caché según el ciclo de vida del contenido. Las descripciones e imágenes de los productos pueden cambiar despacio; el precio y el inventario requieren un contrato más estricto. Guarda en caché las lecturas estables del catálogo con etiquetas de producto y categoría, y revalídalas tras una actualización aprobada. El proceso de pago siempre vuelve a cargar los valores transaccionales.
Trata el carrito como una propuesta
Un cliente anónimo puede recibir un token aleatorio del carrito en una cookie HTTP-only, cuyo registro en la base de datos guarda los IDs de las variantes y las cantidades. Tras iniciar sesión, fusiónalo con el carrito del cliente mediante reglas explícitas para duplicados, variantes no disponibles y límites de cantidad. No guardes los precios de referencia en una cookie modificable.
La página del carrito puede mostrar una estimación calculada, pero cada mutación y solicitud de pago debe volver a cargar en el servidor las variantes, los precios, los límites de compra y el inventario. Devuelve correcciones por línea cuando cambie un producto, en lugar de cobrar silenciosamente un importe distinto.
Completa el pago de forma asíncrona
Crea la sesión de Stripe Checkout en el servidor a partir del carrito validado y adjunta como metadato un ID estable del carrito o del pedido pendiente. La URL de retorno puede mostrar que se está confirmando el pago, pero no puede crear por sí sola el pedido final.
Verifica la firma de Stripe con el cuerpo original del webhook, registra el ID del evento bajo una restricción de unicidad y crea o avanza el pedido exactamente una vez. Gestiona explícitamente las sesiones completadas y caducadas, los fallos de pago, los reembolsos y los eventos repetidos. Pon en cola el correo y la preparación del pedido cuando exista un estado persistente del pedido.
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: pricedCart.lines.map((line) => ({
price: line.stripePriceId,
quantity: line.quantity,
})),
success_url: SITE_URL + "/orders/confirm?session_id={CHECKOUT_SESSION_ID}",
cancel_url: SITE_URL + "/cart",
metadata: { pendingOrderId: pendingOrder.id },
});Mantén el inventario transaccional
Decide cuándo se reserva el stock: al añadir al carrito, al crear el proceso de pago o al confirmar el pago. Reservar al añadir al carrito reduce la disponibilidad aparente y exige una caducidad rápida; reservar al pagar puede aceptar más procesos de pago simultáneos que unidades disponibles. El modelo de preparación de pedidos determina qué compromiso asumir.
Sea cual sea la política que elijas, actualiza el inventario de forma atómica e impide cantidades negativas en la base de datos. Registra la caducidad de las reservas y concilia explícitamente los eventos de pago tardíos. Las cachés pueden publicar la disponibilidad, pero la tabla de inventario y la transacción deciden si un pedido puede obtener stock.
Facilita el descubrimiento de productos y el SEO
Define expresamente un modelo canónico para cada producto. Genera títulos, descripciones, imágenes Open Graph, JSON-LD Product y Offer, rutas de navegación y entradas del sitemap a partir de los registros publicados. Mantén el precio y la disponibilidad coherentes con la página visible y el proceso de pago.
Las páginas de categorías deben enlazar a los productos importantes mediante enlaces reales. Trata los filtros como estado de la aplicación, salvo que una combinación seleccionada tenga demanda y contenido propios. Para los productos descatalogados, decide expresamente entre 200, redirección, 404 o 410 según si la página sigue ayudando a los clientes.
Despliega y prueba el flujo de la transacción
Adios ejecuta el servidor completo de producción de Next.js como un proceso persistente: los Server Components, los endpoints del carrito, los webhooks firmados y las páginas de pedidos comparten una versión. El manifiesto declara la compilación, el inicio, la ruta de salud, la dependencia de base de datos y las referencias a secretos junto al código fuente.
Despliega una vista previa y prueba el HTML de los productos, un carrito manipulado, dos compradores simultáneos, Checkout en modo de prueba, eventos duplicados, una sesión caducada, la entrega al sistema de correo y un producto desconocido. Inspecciona los registros de compilación y del entorno de ejecución, y promueve la versión solo cuando la aplicación indique que está saludable. El dominio personalizado y TLS gestionado permanecen asociados a la versión verificada.
adios.yaml
name: trail-supply
build_cmd: npm ci && npm run build
start_cmd: npm start
runtime:
name: node@24
port: 3000
health_path: /api/health
requires:
- db
env:
DATABASE_URL: secret://DATABASE_URL
STRIPE_SECRET_KEY: secret://STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET: secret://STRIPE_WEBHOOK_SECRET