Terminar de construir una aplicación y no saber cómo publicarla es una de las barreras más comunes para los desarrolladores que empiezan. Configurar un servidor, gestionar SSH, instalar dependencias manualmente… todo eso era el proceso normal hace unos años. Hoy existen plataformas que permiten desplegar una aplicación en producción en menos de cinco minutos, con un plan gratuito más que suficiente para proyectos personales, portfolios y prototipos.
Vercel y Render son las dos mejores opciones gratuitas del mercado en 2026. En esta guía aprenderás qué ofrece cada una, cuándo elegir una u otra, y cómo desplegar paso a paso proyectos reales: una app de Next.js en Vercel y una API de Node.js con base de datos en Render.
Vercel vs Render: cuál es la diferencia
Vercel es la plataforma creada por el mismo equipo que desarrolla Next.js. Está optimizada para frontends, aplicaciones JAMstack y frameworks de React como Next.js, Nuxt, SvelteKit y Astro. Su modelo de despliegue es el de las funciones serverless y el edge: el código no corre en un servidor siempre activo, sino que se ejecuta bajo demanda cerca del usuario. Es extremadamente rápida para contenido estático y SSR.
Render está pensado para aplicaciones backend: APIs REST, servicios Node.js, Python, Go, Ruby, aplicaciones full-stack, bases de datos PostgreSQL y Redis, y workers en segundo plano. A diferencia de Vercel, en Render tienes servidores que corren continuamente (aunque en el plan gratuito se duermen tras 15 minutos de inactividad).
La elección depende de lo que quieras desplegar:
- Frontend React/Next.js, sitio estático, SSR → Vercel
- API REST Node.js/Python/Java, app full-stack con base de datos → Render
- Proyecto full-stack con frontend y backend separados → Vercel para el frontend + Render para el backend
Parte 1: Desplegar en Vercel
Qué incluye el plan gratuito de Vercel
- Proyectos ilimitados para uso personal
- 100 GB de ancho de banda al mes
- Despliegues automáticos en cada push a Git
- Previews automáticos para cada Pull Request
- SSL/HTTPS automático en todos los dominios
- CDN global (edge network) en más de 100 ubicaciones
- Dominio gratuito
.vercel.app - Variables de entorno por proyecto y por entorno
Paso 1: Preparar el repositorio
Vercel se conecta directamente con GitHub, GitLab o Bitbucket. Tu código debe estar en alguno de estos servicios antes de empezar.
Para este ejemplo, una app Next.js básica. Si no tienes una, créala:
npx create-next-app@latest mi-app-nextjs
cd mi-app-nextjs
# Verifica que funciona localmente
npm run dev
# Visita http://localhost:3000
Sube el proyecto a GitHub:
git init
git add .
git commit -m "primer commit"
git branch -M main
git remote add origin https://github.com/tu-usuario/mi-app-nextjs.git
git push -u origin main
Paso 2: Conectar con Vercel
- Ve a vercel.com y crea una cuenta. La forma más rápida es hacerlo con tu cuenta de GitHub.
- En el dashboard haz clic en "Add New Project".
- Vercel pide acceso a tus repositorios de GitHub. Puedes dar acceso a todos o solo al repositorio específico.
- Selecciona mi-app-nextjs de la lista.
Paso 3: Configurar el despliegue
Vercel detecta automáticamente que es un proyecto Next.js y configura todo sin que toques nada. En la pantalla de configuración verás:
- Framework Preset: Next.js (detectado automáticamente)
- Root Directory:
./(la raíz del repositorio) - Build Command:
npm run build(autodetectado) - Output Directory:
.next(autodetectado)
Si tu proyecto necesita variables de entorno (claves de API, URLs de base de datos), añádelas en la sección Environment Variables antes de desplegar:
# Variables de ejemplo que podrías necesitar
NEXT_PUBLIC_API_URL=https://api.tu-backend.com
DATABASE_URL=postgresql://usuario:password@host/db
NEXTAUTH_SECRET=tu_secreto_aleatorio
Las variables con el prefijo NEXT_PUBLIC_ son accesibles desde el navegador (frontend). Las que no tienen ese prefijo solo están disponibles en el servidor.
Haz clic en "Deploy". Vercel construye la aplicación y la despliega en su red global. El proceso suele tardar entre 30 y 90 segundos.
Paso 4: Tu app está en producción
Al terminar, Vercel te da una URL del tipo mi-app-nextjs.vercel.app. Desde ese momento, cada vez que hagas un git push a la rama main, Vercel redespliega automáticamente la aplicación.
Además, cada Pull Request genera automáticamente una URL de preview única con esa versión del código, lo que facilita enormemente la revisión de cambios antes de mergear.
Añadir un dominio personalizado
# En el panel de Vercel, ve a tu proyecto → Settings → Domains
# Añade tu dominio: tudominio.com
# Luego en tu proveedor de DNS, añade estos registros:
# Tipo A @ → 76.76.21.21
# Tipo CNAME www → cname.vercel-dns.com
# Vercel genera el certificado SSL automáticamente en minutos
Vercel CLI: desplegar desde la terminal
# Instalar Vercel CLI globalmente
npm install -g vercel
# Autenticarse
vercel login
# Desplegar desde la carpeta del proyecto
vercel
# Vercel hace preguntas la primera vez:
# ? Set up and deploy "mi-app"? → y
# ? Which scope? → tu-usuario
# ? Link to existing project? → N
# ? What's your project's name? → mi-app-nextjs
# ? In which directory is your code located? → ./
# Para desplegar a producción directamente:
vercel --prod
# Ver los logs de un despliegue
vercel logs
# Gestionar variables de entorno desde CLI
vercel env add DATABASE_URL production
vercel env ls
Parte 2: Desplegar en Render
Qué incluye el plan gratuito de Render
- Web Services: 750 horas/mes de ejecución (suficiente para un servicio 24/7)
- El servicio se duerme tras 15 minutos de inactividad (se despierta en ~30 segundos)
- SSL/HTTPS automático
- Dominio gratuito
.onrender.com - PostgreSQL gratuito: 1 GB de almacenamiento, 90 días de duración (renovable)
- Deploy automático en cada push a Git
- Logs en tiempo real
La limitación del "sleep" en el plan gratuito es la más notable: si nadie visita tu app durante 15 minutos, Render la pone en modo de espera. La siguiente petición la despierta, pero hay una espera inicial de unos 30 segundos. Para APIs de producción real necesitas el plan de pago ($7/mes). Para proyectos de aprendizaje, portfolios y prototipos, el plan gratuito es perfectamente válido.
Paso 1: Preparar una API Node.js
mkdir mi-api && cd mi-api
npm init -y
npm install express dotenv
// index.js
const express = require('express');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({ mensaje: 'API funcionando', version: '1.0.0' });
});
app.get('/salud', (req, res) => {
res.json({ estado: 'ok', timestamp: new Date().toISOString() });
});
app.get('/usuarios', (req, res) => {
res.json([
{ id: 1, nombre: 'Ana García', email: 'ana@mail.com' },
{ id: 2, nombre: 'Carlos López', email: 'carlos@mail.com' },
]);
});
app.listen(PORT, () => {
console.log(`Servidor escuchando en puerto ${PORT}`);
});
// package.json — añadir script de start
{
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
}
}
Render usa el script npm start para arrancar la aplicación. Asegúrate de que existe y de que usa la variable de entorno PORT que Render asigna dinámicamente.
Sube el proyecto a GitHub (igual que antes). Añade un .gitignore:
# .gitignore
node_modules/
.env
.DS_Store
Paso 2: Crear el servicio en Render
- Ve a render.com y crea una cuenta con GitHub.
- En el dashboard haz clic en "New +" y selecciona "Web Service".
- Conecta tu cuenta de GitHub y selecciona el repositorio mi-api.
Configura el servicio:
- Name: mi-api (o cualquier nombre)
- Region: Frankfurt EU Central (o la más cercana a tus usuarios)
- Branch: main
- Runtime: Node
- Build Command:
npm install - Start Command:
npm start - Instance Type: Free
Paso 3: Variables de entorno en Render
En la sección Environment Variables añade las variables que necesite tu aplicación:
# Variables que normalmente necesita una API
NODE_ENV=production
JWT_SECRET=tu_clave_secreta_muy_larga_y_aleatoria
DATABASE_URL=postgresql://... # lo añadirás después de crear la BD
Haz clic en "Create Web Service". Render instalará las dependencias, arrancará la aplicación y te dará una URL del tipo mi-api.onrender.com.
Paso 4: Crear una base de datos PostgreSQL gratuita
# En el dashboard de Render: New + → PostgreSQL
# Configuración:
# Name: mi-db
# Region: Frankfurt EU Central (misma que el servicio)
# Plan: Free
# Version: 16
# Render genera automáticamente:
# Internal Database URL: postgresql://usuario:pass@dpg-xxx/mi_db
# External Database URL: postgresql://usuario:pass@oregon-postgres.render.com/mi_db
Usa la Internal Database URL para conectar tu API con la base de datos (comunicación interna dentro de Render, más rápida y sin coste de transferencia). La External URL es para conectarte desde tu máquina local con herramientas como TablePlus o DBeaver.
Copia la Internal URL y añádela como variable de entorno en tu Web Service:
DATABASE_URL=postgresql://usuario:pass@dpg-xxxxxxxxxx-a/mi_dbPaso 5: Conectar la API a PostgreSQL
npm install pg dotenv// db.js — configuración de la conexión
const { Pool } = require('pg');
require('dotenv').config();
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production'
? { rejectUnauthorized: false } // Render requiere SSL en producción
: false
});
module.exports = pool;
// index.js — usando la base de datos
const express = require('express');
const pool = require('./db');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3000;
// Crear tabla al arrancar (en producción usa migraciones con Flyway o Knex)
pool.query(`
CREATE TABLE IF NOT EXISTS usuarios (
id SERIAL PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
creado_en TIMESTAMP DEFAULT NOW()
)
`).then(() => console.log('Tabla usuarios lista'));
app.get('/usuarios', async (req, res) => {
try {
const result = await pool.query('SELECT * FROM usuarios ORDER BY creado_en DESC');
res.json(result.rows);
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Error interno del servidor' });
}
});
app.post('/usuarios', async (req, res) => {
const { nombre, email } = req.body;
if (!nombre || !email) {
return res.status(400).json({ error: 'Nombre y email son obligatorios' });
}
try {
const result = await pool.query(
'INSERT INTO usuarios (nombre, email) VALUES ($1, $2) RETURNING *',
[nombre, email]
);
res.status(201).json(result.rows[0]);
} catch (error) {
if (error.code === '23505') { // unique violation
return res.status(409).json({ error: 'El email ya está registrado' });
}
res.status(500).json({ error: 'Error interno del servidor' });
}
});
app.listen(PORT, () => console.log(`Servidor en puerto ${PORT}`));
Haz push a GitHub y Render redespliega automáticamente:
git add .
git commit -m "conectar API con PostgreSQL"
git push origin main
Render detecta el push, instala dependencias, reinicia el servicio y en 1-2 minutos la API está actualizada en producción.
Render CLI: desplegar desde la terminal
# Instalar Render CLI
npm install -g @render-oss/cli
# Autenticarse
render login
# Ver todos tus servicios
render services list
# Ver logs en tiempo real de un servicio
render logs --service tu-servicio-id --tail
# Forzar un redeploy manual
render deploys create --service tu-servicio-id
# Gestionar variables de entorno
render env set DATABASE_URL=postgresql://... --service tu-servicio-id
render env list --service tu-servicio-id
Desplegar una app full-stack: Vercel + Render
El patrón más común para proyectos personales es usar Vercel para el frontend y Render para el backend. La arquitectura queda así:
# Estructura del proyecto
mi-proyecto/
├── frontend/ → Next.js, desplegado en Vercel
└── backend/ → Express/Node.js + PostgreSQL, desplegado en Render
// frontend/.env.local — URL del backend en producción
NEXT_PUBLIC_API_URL=https://mi-backend.onrender.com
// frontend/.env.development.local — URL del backend en local
NEXT_PUBLIC_API_URL=http://localhost:3001
// frontend/lib/api.js — cliente para llamar al backend
const API_URL = process.env.NEXT_PUBLIC_API_URL;
export async function obtenerUsuarios() {
const res = await fetch(`${API_URL}/usuarios`);
if (!res.ok) throw new Error('Error al obtener usuarios');
return res.json();
}
export async function crearUsuario(datos) {
const res = await fetch(`${API_URL}/usuarios`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(datos)
});
if (!res.ok) throw new Error('Error al crear usuario');
return res.json();
}
Un punto crítico: si tu frontend en Vercel hace peticiones a tu backend en Render, necesitas configurar CORS en el backend para permitir el dominio de Vercel:
// backend/index.js — configurar CORS
const cors = require('cors');
npm install cors
const DOMINIOS_PERMITIDOS = [
'http://localhost:3000',
'https://mi-frontend.vercel.app',
'https://mi-dominio-personalizado.com'
];
app.use(cors({
origin: (origin, callback) => {
// Permitir peticiones sin origen (Postman, curl) y dominios de la lista
if (!origin || DOMINIOS_PERMITIDOS.includes(origin)) {
callback(null, true);
} else {
callback(new Error('No permitido por CORS'));
}
},
credentials: true // si usas cookies de sesión
}));
Otras plataformas gratuitas que vale la pena conocer
Railway es una alternativa a Render con una experiencia de usuario muy pulida. Tiene soporte para prácticamente cualquier lenguaje y base de datos, y su plan gratuito ofrece $5 de crédito mensual (suficiente para proyectos pequeños). La configuración es incluso más sencilla que la de Render para proyectos complejos con múltiples servicios.
Netlify compite directamente con Vercel para frontends y sitios estáticos. Tiene funciones serverless, formularios integrados y un plan gratuito generoso. Si ya conoces Vercel, no hay razón de peso para cambiarse, pero si buscas una alternativa, Netlify es sólida.
Fly.io permite desplegar aplicaciones en contenedores Docker con una CLI muy potente. Tiene plan gratuito para proyectos pequeños y es la opción más flexible de todas para backends complejos o aplicaciones que requieren control sobre el entorno de ejecución.
Supabase ya lo conoces como base de datos, pero también ofrece Edge Functions para lógica de servidor sin necesidad de un backend separado. Si tu proyecto usa Supabase como base de datos, sus funciones pueden reemplazar a un servidor Express para la mayoría de casos de uso.
Buenas prácticas para despliegues en producción
Nunca subas secretos al repositorio. Las API keys, contraseñas de base de datos y secretos JWT siempre van como variables de entorno en la plataforma de despliegue, nunca en el código ni en archivos .env subidos a Git. Añade .env a tu .gitignore antes del primer commit.
Configura un dominio personalizado desde el principio. Las URLs de .vercel.app y .onrender.com son funcionales pero no profesionales. Comprar un dominio cuesta entre 10 y 15 euros al año y tanto Vercel como Render lo configuran automáticamente con SSL.
Monitoriza los errores en producción. Servicios como Sentry tienen plan gratuito y te mandan alertas cuando hay errores en la aplicación. Integrar Sentry toma menos de 10 minutos y es la diferencia entre enterarte de los errores antes que tus usuarios o después.
# Integrar Sentry en Node.js
npm install @sentry/node
// Al inicio de index.js
const Sentry = require('@sentry/node');
Sentry.init({ dsn: process.env.SENTRY_DSN });
app.use(Sentry.Handlers.requestHandler());
// Después de todas las rutas
app.use(Sentry.Handlers.errorHandler());
Añade un endpoint de healthcheck. Render y otras plataformas pueden comprobar periódicamente si tu servicio está vivo. Un endpoint simple es suficiente:
app.get('/health', (req, res) => {
res.json({
estado: 'ok',
timestamp: new Date().toISOString(),
version: process.env.npm_package_version
});
});
Usa ramas de Git para separar entornos. El flujo estándar es: main → producción, develop → staging. Tanto Vercel como Render permiten configurar qué rama desencadena el despliegue a producción, y qué otras ramas generan entornos de preview.
Resumen
- Vercel es la mejor opción para frontends con Next.js, sitios estáticos y apps con SSR. Despliegue en un clic desde GitHub, CDN global y SSL automático. Plan gratuito muy generoso.
- Render es la mejor opción para APIs y backends con Node.js, Python u otros lenguajes, especialmente si necesitas una base de datos PostgreSQL gratuita. La limitación del plan gratuito es el sleep tras 15 minutos de inactividad.
- Para proyectos full-stack, el patrón habitual es Vercel para el frontend + Render para el backend, configurando la URL del backend como variable de entorno en Vercel y CORS en el backend para permitir el dominio de Vercel.
- Nunca subas secretos al repositorio: usa siempre variables de entorno en la plataforma.
- Ambas plataformas despliegan automáticamente en cada
git push, lo que elimina completamente el proceso manual de despliegue.
No hay comentarios todavía. Sé el primero en compartir tu opinión.