Next.js SaaS
Cómo crear un SaaS con Next.js para producción: autenticación, facturación, tareas y despliegue
Crea un SaaS de producción con Next.js 16, autenticación, Postgres, suscripciones, trabajo en segundo plano, configuración segura, pruebas y despliegue.
Un SaaS se complica donde las funcionalidades interactúan con el estado: identidad, autorización, facturación, reintentos, migraciones y versiones. El árbol de componentes de React es solo una parte del sistema.
Define el primer ciclo completo del cliente
Empieza con un ciclo que un cliente pueda completar: descubrir el producto, crear una cuenta, completar la incorporación, crear el recurso principal, recibir el resultado y volver más tarde para encontrar el mismo estado. Esto revela los límites reales del sistema antes que un largo inventario de funcionalidades.
Escribe las transiciones de estado junto a las pantallas. Indica quién puede realizar cada transición, qué registros cambian, qué llamadas externas se producen y qué sucede si una llamada se repite o falla. Un SaaS fiable se diseña en torno a esas transiciones, no a una colección de tarjetas del panel.
- —Rutas públicas de captación y documentación.
- —Autenticación, sesión y recuperación de cuentas.
- —El objeto de dominio primario y sus reglas de propiedad.
- —Un derecho de acceso asociado a la facturación o un límite explícito del plan gratuito.
- —Pruebas de correo, tareas, auditoría y fallos.
Separa el código público, el de la aplicación y el exclusivo del servidor
Usa grupos de rutas para dar a las rutas de marketing y de la aplicación autenticada diseños distintos sin cambiar sus URLs. Mantén las páginas y los layouts como Server Components y añade Client Components a los formularios y controles que necesiten estado del navegador. Esto mantiene el contenido público rastreable y reduce el JavaScript del panel.
Coloca el acceso a bases de datos, la autorización, los adaptadores de facturación y las integraciones con secretos en módulos exclusivos del servidor. Una capa de acceso a datos concentra las lecturas seguras en un lugar auditable. Las Server Actions gestionan las mutaciones iniciadas por la interfaz de React; los Route Handlers gestionan webhooks, comprobaciones de salud e interfaces HTTP usadas fuera de esa interfaz.
A practical SaaS route tree
src/app/
├── (marketing)/page.tsx
├── (marketing)/pricing/page.tsx
├── (auth)/login/page.tsx
├── (app)/dashboard/page.tsx
├── (app)/projects/[id]/page.tsx
├── api/stripe/webhook/route.ts
└── api/health/route.ts
src/lib/
├── auth.ts
├── dal.ts
├── db.ts
└── billing.tsModela la propiedad en la base de datos
Usa una base de datos relacional para cuentas, pertenencias, registros de dominio, derechos de acceso, eventos webhook y tareas que requieran transacciones y restricciones. Asigna a cada registro con propietario una clave de cuenta o tenant. Impón la unicidad y las claves foráneas en la base de datos para que la concurrencia no pueda eludir las suposiciones del código de la aplicación.
Las migraciones son código de producción. Primero añade los cambios, rellena los datos por separado cuando sea necesario, despliega código que pueda leer la estructura de transición y elimina los campos antiguos más adelante. Una versión no debe asumir que todas las réplicas y tareas cambian de esquema al mismo instante.
Trata la facturación como un estado asíncrono
Checkout inicia un proceso de facturación; no es la autoridad final sobre el estado de la suscripción. Crea la sesión de Checkout en el servidor, redirige al proveedor y actualiza los derechos locales a partir de eventos webhook verificados. Guarda los IDs del cliente y de la suscripción del proveedor junto a la cuenta propietaria.
Procesa los reintentos de forma segura registrando los IDs de eventos bajo una restricción de unicidad. Gestiona explícitamente la activación, los cambios de plan, los pagos fallidos, la cancelación y la eliminación. Decide qué acciones requieren un derecho de acceso activo y cómo afecta un período de gracia al acceso. La interfaz debe leer el estado de facturación local normalizado, en lugar de llamar al proveedor en cada página.
Saca de las solicitudes el trabajo lento y el que admite reintentos
El correo, las importaciones, las exportaciones, la sincronización con proveedores y la generación de informes no deben mantener abierta una solicitud HTTP. Guarda una tarea persistente o emite un evento de flujo de trabajo como parte de la mutación, devuelve un estado útil al usuario y deja que un proceso de trabajo realice el trabajo lento con reintentos y plazos.
Haz las tareas idempotentes, registra los intentos y distingue los fallos del proveedor que admiten reintentos de las entradas inválidas. El panel debe mostrar los estados pendiente, correcto y fallido, en lugar de aparentar que todas las acciones en segundo plano terminan inmediatamente.
- —Identidad estable de la tarea y clave de deduplicación.
- —Reintentos limitados con espera progresiva.
- —Límites de tiempo para las llamadas externas.
- —Un error final que se pueda inspeccionar y una vía de recuperación.
Prueba los límites y la recuperación
Haz pruebas unitarias de las reglas de dominio, pruebas de integración de la capa de acceso a datos y las mutaciones, y pruebas de navegador del registro, la incorporación, el flujo principal y la facturación. Añade casos adversos: un usuario solicita un registro de otra cuenta, un webhook se repite, varias operaciones compiten por una restricción de base de datos y un proveedor externo agota el tiempo de espera.
Ejecuta la compilación de producción por separado del lint, la comprobación de tipos y las pruebas. Inicia la aplicación compilada con valores de entorno similares a los de producción, aplica las migraciones en un paso controlado y haz pruebas básicas del contenido público, las lecturas autenticadas, una mutación, la ruta webhook y el comportamiento de salud.
Despliega todo el contrato del entorno de ejecución
Adios ejecuta el servidor estándar de producción de Next.js como un proceso persistente de Node.js, de modo que Server Components, Route Handlers, conexiones de base de datos y páginas autenticadas comparten una versión de la aplicación. El manifiesto registra la compilación, el inicio, el puerto, la ruta de salud, los recursos y las referencias a secretos junto al código fuente.
Despliega una vista previa, inspecciona los registros de compilación y del entorno de ejecución, verifica las migraciones y los servicios necesarios, y promueve la versión cuando responda correctamente la ruta de salud. Los dominios personalizados y TLS gestionado permanecen asociados a la versión promovida. Si una versión candidata no puede iniciarse o indicar que está saludable, sus pruebas siguen disponibles sin convertirla en la versión pública saludable.
adios.yaml
name: northstar-saas
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
AUTH_SECRET: secret://AUTH_SECRET
STRIPE_SECRET_KEY: secret://STRIPE_SECRET_KEY