BlogDevOps

Deploy de Next.js 15 en Railway sin Vercel: guía paso a paso

Vercel es excelente, pero tiene un techo de precio que duele cuando eres una startup latinoamericana escalando. Railway te da un servidor real con PostgreSQL, Redis y cron jobs en el mismo proyecto, por mucho menos.

Edward Díaz — Edwsystem30 de abril de 202511 min de lectura

¿Por qué no Vercel?

Vercel es la plataforma canónica para Next.js: DX impecable, previews automáticos, Edge Network global. Para un proyecto personal o una landing, está bien. El problema llega cuando comienzas a necesitar más:

  • Background jobs: en el plan gratuito las funciones cortan a los 10 segundos. Si usas pg-boss o workers asincrónicos, estás fuera.
  • Precio en escala: Vercel Pro cuesta $20/mes por miembro del equipo, más la base de datos externa (Neon, PlanetScale, Supabase). Para un equipo de tres personas en Colombia, eso es una factura seria.
  • Sin estado persistente: cada invocación de función es stateless. Conexiones a la DB se abren y cierran constantemente; sin pooling dedicado, el rendimiento cae.

Railway resuelve estos tres puntos: corre tu app como un proceso Node.js de larga duración, incluye PostgreSQL y Redis en el mismo proyecto, y cobra por uso real (no por asiento).

Qué ofrece Railway

Railway es una plataforma PaaS basada en contenedores (no serverless). Cuando haces deploy de tu Next.js ahí, Railway construye una imagen Docker con Nixpacks y levanta un contenedor que corre continuamente.

Contenedores persistentes

El proceso Node no se apaga entre requests. Conexiones a DB reutilizables.

PostgreSQL y Redis integrados

Un click y tienes la DB en el mismo proyecto. Railway inyecta DATABASE_URL automáticamente.

Cron Jobs nativos

Sin costo adicional. Define el schedule directamente en el dashboard.

Precio justo

$5 de crédito gratis al mes. Después: $0.000463/vCPU-hora y $0.000231/GB-hora de RAM.

Paso 1 — Crear el proyecto en Railway

  1. 1Entra a railway.app y crea una cuenta con GitHub.
  2. 2Click en New Project → Deploy from GitHub repo. Autoriza el repositorio de tu app.
  3. 3Railway detecta Next.js automáticamente vía Nixpacks y propone npm run build y npm run start como comandos. Puedes aceptarlos o sobreescribirlos.
  4. 4Agrega un servicio de PostgreSQL desde el mismo proyecto: click en + New → Database → PostgreSQL. Railway vincula automáticamente la variable DATABASE_URL al servicio de tu app.

Paso 2 — Configuración de build (monorepo)

Si tu repositorio es un monorepo (por ejemplo, Turborepo con apps/web), Railway necesita saber dónde vivé la app. Tienes dos opciones:

Opción A — railway.json en la raíz del repo

{
  "$schema": "https://schema.railway.app/railway-schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "cd apps/web && npm install && npm run build"
  },
  "deploy": {
    "startCommand": "cd apps/web && npm run start",
    "healthcheckPath": "/",
    "healthcheckTimeout": 30,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 3
  }
}

Opción B — nixpacks.toml dentro de apps/web

Si prefieres que cada app del monorepo tenga su propia configuración, puedes colocar un nixpacks.toml dentro de apps/web/ y apuntar el root directory del servicio en Railway a esa carpeta:

# apps/web/nixpacks.toml
[phases.build]
cmds = ["npm run build"]

[start]
cmd = "npm run start"

Para Turborepo con workspace, el comando de build puede incluir el filtro:

# Build command en Railway dashboard (Settings → Build)
npx turbo run build --filter=web

# Start command
node apps/web/.next/standalone/server.js

Si usas output: 'standalone' en next.config.ts, el servidor arranca con node .next/standalone/server.js y el build es más ligero (sin node_modules duplicados). Muy recomendado en Railway.

Paso 3 — next.config.ts recomendado para Railway

Activa el modo standalone para que Railway solo copie lo que necesita en el contenedor, y define los hostnames de imágenes remotas si las usas:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'standalone',

  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'res.cloudinary.com',
      },
    ],
  },

  // Desactiva x-powered-by para no exponer la versión
  poweredByHeader: false,

  // Variables de entorno disponibles en el cliente
  // (solo las que NO son secretas)
  env: {
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL ?? '',
  },
}

export default nextConfig

Paso 4 — Variables de entorno en Railway

Ve a tu servicio → pestaña Variables. Agrega tus variables una a una o importa un .env completo con el botón RAW Editor.

# Railway inyecta esto automáticamente cuando tienes PostgreSQL en el mismo proyecto:
DATABASE_URL=postgresql://postgres:PASSWORD@HOST:5432/railway

# Las tuyas van aquí (ejemplo):
NEXT_PUBLIC_APP_URL=https://tudominio.com
OPENAI_API_KEY=sk-...
JWT_SECRET=un-secreto-largo-y-aleatorio
NODE_ENV=production

Railway vincula los servicios del mismo proyecto con variables de referencia. Si agregas Redis, la variable REDIS_URL también se inyecta automáticamente — no tienes que copiar y pegar URLs entre servicios.

Si cambias una variable de entorno, Railway hace redeploy automático. Puedes desactivar este comportamiento en Settings → Auto-Deploy si prefieres controlar cuándo se aplican los cambios.

La diferencia fundamental: Node.js server vs serverless

En Vercel, cada route handler es una función Lambda. Se levanta, responde y muere. En Railway, tu app corre como un proceso next start que vive continuamente. Esto cambia todo:

CaracterísticaRailway (Node)Vercel (Serverless)
Timeout máximoIlimitado10s (hobby) / 300s (pro)
Background jobs✓ Sí (pg-boss, cron)✗ No nativo
Conexiones DB persistentes✓ Pool reutilizable✗ Reconecta por invocación
Edge Runtime✗ Todo es Node✓ Sí (con limitaciones)
ISR / On-demand revalidation✓ Funciona✓ Optimizado en Vercel
WebSockets✓ Sí✗ No en funciones

En la práctica, en edwsystem.com corremos pg-boss para procesar leads en background, enviar emails y ejecutar integraciones con IA. Nada de eso funciona en el plan gratuito de Vercel.

Paso 5 — Dominio personalizado y SSL

Railway genera un dominio *.up.railway.app automáticamente. Para usar tu propio dominio:

  1. 1Ve a Settings → Networking → Custom Domain y escribe tu dominio (ej. edwsystem.com).
  2. 2Railway te da un registro CNAME (para subdominios) o un registro A (para el apex). Agrégalo en tu registrador (GoDaddy, Cloudflare, Namecheap, etc.).
  3. 3Railway emite el certificado SSL vía Let's Encrypt automáticamente una vez que el DNS propaga (generalmente menos de 5 minutos con Cloudflare).
# Ejemplo de configuración DNS en Cloudflare (modo proxy OFF para SSL de Railway)
# Tipo    Nombre    Contenido                           TTL
CNAME     www       myapp-production.up.railway.app     Auto
A         @         [IP que Railway proporciona]        Auto

Si usas Cloudflare como proxy (nube naranja), desactívalo temporalmente o configura el modo Full (Strict) para que Cloudflare confíe en el certificado de Railway. De lo contrario, obtendrás errores de SSL.

Paso 6 — Health checks y deploys sin downtime

Railway hace rolling deployments: levanta el nuevo contenedor, espera que el healthcheck pase, y solo entonces elimina el viejo. Configura el healthcheck en railway.json o en el dashboard:

// En railway.json
{
  "deploy": {
    "healthcheckPath": "/api/health",
    "healthcheckTimeout": 30
  }
}

// app/api/health/route.ts
export async function GET() {
  return Response.json({ status: 'ok', ts: Date.now() })
}

Si el nuevo deploy falla el healthcheck tres veces consecutivas, Railway revierte al contenedor anterior automáticamente. Define la política de restart:

{
  "deploy": {
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 3
  }
}

Monitoreo: logs, métricas y alertas

Railway incluye observabilidad básica sin configuración adicional:

  • Logs en tiempo real desde el dashboard o con la CLI: railway logs --tail
  • Métricas de CPU y RAM con gráficas históricas en la pestaña Metrics del servicio.
  • Alertas por email o Slack cuando un servicio se cae o supera el uso de RAM configurado.

Para logging estructurado en producción, usa pino con formato JSON. Railway parsea los logs JSON automáticamente y te permite filtrarlos por campo.

Comparativa de costos real

Nuestro stack en producción: Next.js 15 + PostgreSQL + Redis + pg-boss. Consumo promedio: 0.5 vCPU y 512 MB RAM por servicio.

ÍtemRailwayVercel Pro + Neon
App (Next.js)~$5/mes$20/mes (por usuario)
PostgreSQL~$5/mes (incluido)$19/mes (Neon Pro)
Redis~$2/mes (incluido)$7/mes (Upstash)
Dominios / SSLGratisGratis
Total estimado~$12/mes~$46/mes

Para una startup colombiana, la diferencia de ~$34/mes equivale a más de $136.000 COP al mes (a tasa de cambio de abril 2025). Con ese ahorro, cubres el dominio y algo más.

¿Cuándo seguir usando Vercel?

Railway no es mejor en todos los casos. Usa Vercel cuando:

  • Tu app es puramente serverless sin necesidad de procesos de larga duración ni estado en memoria.
  • Usas intensivamente ISR (Incremental Static Regeneration) y quieres el caché distribuido en el Edge de Vercel sin configurar nada extra.
  • Necesitas Edge Functions reales que corran en la región más cercana al usuario (< 10ms latencia en todo el mundo).
  • El equipo es grande y el valor del DX de Vercel (previews por PR, comentarios de equipo) justifica el precio.

Resumen: el flujo completo

# 1. Activa output standalone en next.config.ts
output: 'standalone'

# 2. Crea railway.json en la raíz del repo (monorepo)
#    Con buildCommand, startCommand, healthcheckPath

# 3. En Railway dashboard:
#    - New Project → GitHub repo
#    - + New → Database → PostgreSQL  (DATABASE_URL se inyecta sola)
#    - Settings → Networking → Custom Domain
#    - Variables → agregar secrets

# 4. Primer deploy automático en cada push a main
#    Railway: build → healthcheck → swap → zero-downtime

# 5. Monitoreo: railway logs --tail  |  dashboard Metrics tab

En Edwsystem llevamos más de seis meses con este setup en producción. El tiempo de deploy es de ~3 minutos (build de Next.js incluido), el uptime está en 99.9% y el costo total no supera los $15/mes con tráfico moderado. Si estás evaluando opciones para tu próximo proyecto SaaS, Railway merece estar en la lista.

¿Te fue útil este artículo?

Déjame tu email y te aviso cuando publique nuevos artículos técnicos.