Montar un side project y dejarlo publicado sin gastar un euro es perfectamente posible. El stack Next.js + Prisma + Postgres desplegado en Vercel cubre el caso típico: una app con base de datos relacional, despliegues automáticos por rama y un coste inicial de cero. En Julditec llevamos años poniendo software en producción con variantes más grandes de este mismo esquema (pool de conexiones, variables de entorno por entorno, CI/CD), así que vamos a explicar cómo se monta bien desde el primer commit, porque los errores que se cometen en un side project son los mismos que luego duelen en un proyecto serio.
Arrancar el proyecto: create-next-app y Postgres gratuito
El punto de partida es el de siempre:
npx create-next-app@latest mi-proyecto
cd mi-proyecto
npm install prisma --save-dev
npm install @prisma/client
npx prisma initEsto genera la carpeta prisma con un schema.prisma y un fichero .env. Lo siguiente es decidir dónde vive la base de datos. Para una capa gratuita razonable hay dos opciones claras:
Neon o Supabase
- •Neon: Postgres serverless con autoescalado y una conexión "pooled" lista para usar, pensada específicamente para entornos sin estado como las funciones de Vercel.
- •Supabase: Postgres gestionado con extras (auth, storage, API REST automática) que pueden sobrarte para un proyecto pequeño, pero que están ahí si crece.
Para un side project sin pretensiones, Neon suele ser la opción más directa porque el pooling de conexiones viene resuelto de fábrica. Si ya tienes pensado usar autenticación o storage de archivos, Supabase te ahorra añadir otro servicio más adelante.
Schema, migraciones y el comando que falla si lo olvidas
Con la cadena de conexión en el .env, define el schema:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
createdAt DateTime @default(now())
}En local, las migraciones se crean con npx prisma migrate dev. El problema aparece en producción: Vercel ejecuta el build en cada despliegue, pero no aplica migraciones por sí solo. Hay que decírselo explícitamente en package.json:
{
"scripts": {
"build": "prisma migrate deploy && next build",
"postinstall": "prisma generate"
}
}El orden importa: primero se aplican las migraciones pendientes contra la base de datos real, y solo después se compila la app. Si se te olvida el migrate deploy en el build, el despliegue funciona pero la app peta en cuanto intenta leer una tabla que no existe todavía.
Los problemas típicos de Prisma en serverless
La mayoría de side projects se atascan en este punto la primera vez que algo falla de forma intermitente.
Demasiadas conexiones: pooling y singleton del cliente
Cada función serverless de Vercel puede arrancar una instancia nueva, y cada instancia que crea su propio PrismaClient abre una conexión a Postgres. Con tráfico moderado se agota el límite de conexiones del plan gratuito en minutos. Dos soluciones complementarias:
- •Usar la cadena de conexión pooled que te da Neon o Supabase (normalmente con un puerto o parámetro distinto al de la conexión directa, pensada para PgBouncer).
- •Reutilizar el cliente con un singleton en lugar de instanciarlo en cada request.
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma =
globalForPrisma.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}Este patrón evita que el hot reload de desarrollo abra un cliente nuevo cada vez que guardas un fichero, y en producción reduce el número de instancias activas al mínimo necesario.
prisma generate en el postinstall
Si prisma generate no se ejecuta tras el npm install, el cliente que importa tu código no coincide con el schema actual y Vercel lanza errores de tipos en pleno build. Por eso el postinstall del ejemplo anterior no es opcional: sin él, el despliegue falla de forma críptica.
El arranque en frío
Las funciones serverless que llevan un rato sin recibir tráfico se "duermen". La primera petición después de ese letargo tarda más: hay que inicializar el runtime, cargar el cliente de Prisma y, si la conexión a la base de datos también estaba inactiva, reestablecerla. En un side project esto se nota como una primera carga lenta tras un rato sin visitas. No tiene mucho arreglo en la capa gratuita más allá de mantener el cliente reutilizado (el singleton ya ayuda) y evitar lógica pesada en el arranque de cada función.
Variables de entorno y preview deployments por rama
En el panel de Vercel, la variable DATABASE_URL se configura por entorno: Production, Preview y Development. Esto permite un flujo cómodo:
- •La rama main apunta a la base de datos de producción.
- •Cada pull request genera un preview deployment con su propia URL, que puede apuntar a la misma base de datos (si solo quieres ver cambios de UI) o a una base de datos de pruebas separada (si vas a tocar el schema).
Para proyectos pequeños suele bastar con una sola base de datos y cuidado con las migraciones destructivas en preview. Para algo algo más serio, crear una rama de base de datos aparte (Neon lo permite de forma nativa con "branching" de bases de datos) evita sustos.
Los límites de la capa gratuita y cuándo dejan de compensar
Todo esto funciona a coste cero hasta que el proyecto deja de ser pequeño. Los límites habituales a vigilar:
- •Horas de cómputo o almacenamiento en el plan gratuito de Neon o Supabase, que se agotan con tráfico sostenido o bases de datos que crecen de tamaño.
- •Límite de conexiones concurrentes, que un pooling mal configurado puede saturar aunque el tráfico sea moderado.
- •Tiempo de ejecución de las funciones en Vercel, que en el plan gratuito es más corto y puede cortar consultas lentas o procesos en lote.
- •Pausas automáticas de la base de datos por inactividad, que añaden latencia extra a la ya existente por el arranque en frío.
Cuando el proyecto empieza a tener usuarios reales, a programar tareas en segundo plano o a necesitar conexiones estables fuera del ciclo serverless, la capa gratuita deja de ser una base técnica y pasa a ser una limitación de producto.
Imagina una pequeña herramienta interna para gestionar reservas de salas en una oficina: funciona perfectamente gratis mientras la usan quince personas un par de veces al día. En cuanto se convierte en la aplicación que usa toda la empresa a diario, los límites de conexiones y de cómputo empiezan a notarse, y ese es el momento de evaluar un plan de pago o una base de datos dedicada, no antes.
La recomendación práctica es sencilla: monta el side project con esta arquitectura sin miedo, pero deja el singleton del cliente y la cadena pooled configurados desde el primer commit. Son dos líneas de código que cuestan nada al principio y que evitan una migración dolorosa el día que el proyecto empiece a funcionar de verdad.
