Singleton
Problema
Sección titulada «Problema»Algunos recursos (una conexión a base de datos, un cliente de Redis, un pool de workers) deben existir una sola vez por proceso. Crear una instancia nueva en cada import desperdicia conexiones y puede agotar el límite del proveedor.
El módulo de JS/TS ya es un singleton
Sección titulada «El módulo de JS/TS ya es un singleton»Node y los módulos ECMAScript (ESM) almacenan el módulo en caché la primera vez que se importa: se ejecuta una sola vez y todos los import posteriores reciben el mismo objeto exportado. No hace falta la ceremonia de una clase con getInstance() estático que se ve en lenguajes sin este comportamiento.
import { PrismaClient } from "@prisma/client"
export const db = new PrismaClient()import { createClient } from "redis"
const client = createClient({ url: process.env.REDIS_URL })await client.connect()
export const redis = clientCualquier archivo que haga import { db } from '@/libs/db' recibe la misma instancia, ya conectada. Eso es Singleton, gratis, por cómo funciona el sistema de módulos.
Cómo se ve en lenguajes sin este cacheo
Sección titulada «Cómo se ve en lenguajes sin este cacheo»// Así se emula el patrón cuando el lenguaje no almacena módulos en caché.// En JS/TS casi nunca hace falta escribir esto:class Database { private static instance: Database private constructor() {} static getInstance(): Database { if (!Database.instance) Database.instance = new Database() return Database.instance }}Si ves este patrón en un proyecto JS/TS, casi siempre se puede reemplazar por un módulo que exporta la instancia directamente.
Cuándo NO usarlo (o usarlo con cuidado)
Sección titulada «Cuándo NO usarlo (o usarlo con cuidado)»- Estado global compartido dificulta el testing: un mock de
dben un test puede contaminar otros tests si no se resetea entre corridas. - Si necesitas instancias configuradas distinto según contexto (una DB en memoria para tests, la real en producción), inyección de dependencias — pasar la instancia como parámetro — es más flexible que un singleton hardcodeado en el módulo.
- En serverless (Lambda, edge functions) el singleton solo “vive” mientras el proceso está caliente: no asumas que sobrevive entre invocaciones frías.