EmDash soporta múltiples backends de base de datos. Elige según tu objetivo de despliegue.
Resumen
| Base de datos | Ideal para | Despliegue |
|---|---|---|
| D1 | Cloudflare Workers | Edge, distribuido globalmente |
| Hyperdrive | PostgreSQL en Cloudflare Workers | Edge, Postgres existente |
| PostgreSQL | Producción Node.js | Cualquier plataforma con Postgres |
| libSQL | Bases de datos remotas | Edge o Node.js |
| SQLite | Node.js, desarrollo local | Servidor único |
Cloudflare D1
D1 es la base de datos SQLite serverless de Cloudflare. Úsala al desplegar en Cloudflare Workers.
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
}),
],
});
Configuración
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
binding | string | — | Nombre del binding D1 de wrangler.jsonc |
session | string | "disabled" | Modo de replicación de lectura (ver abajo) |
bookmarkCookie | string | "__em_d1_bookmark" | Nombre de cookie para bookmarks de sesión |
Configuración
wrangler.jsonc
{
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-db"
}
]
} wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "emdash-db" Read Replicas
D1 soporta replicación de lectura para reducir la latencia de lectura en sitios distribuidos globalmente. Cuando está habilitada, las consultas de lectura se enrutan a réplicas cercanas en lugar de acceder siempre a la base de datos primaria.
EmDash usa la API de Sesiones D1 para gestionar esto de forma transparente. Habilítalo con la opción session:
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({
binding: "DB",
session: "auto",
}),
}),
],
});
Modos de sesión
| Modo | Comportamiento |
|---|---|
"disabled" | Sin sesiones. Todas las consultas van a la primaria. Predeterminado. |
"auto" | Las solicitudes anónimas leen de la réplica más cercana. Los usuarios autenticados obtienen consistencia read-your-writes via cookies de bookmark. |
"primary-first" | Como "auto", pero la primera consulta siempre va a la primaria. Para sitios con escrituras muy frecuentes. |
Cómo funciona
- Visitantes anónimos obtienen
first-unconstrained— las lecturas van a la réplica más cercana para la menor latencia. Como los usuarios anónimos nunca escriben, no necesitan garantías de consistencia. - Usuarios autenticados (editores, autores) obtienen sesiones basadas en bookmarks. Después de una escritura, una cookie de bookmark asegura que la siguiente solicitud vea al menos ese estado.
- Solicitudes de escritura (
POST,PUT,DELETE) siempre comienzan en la base de datos primaria. - Consultas en tiempo de build (Astro content collections) omiten las sesiones completamente y usan la primaria directamente.
libSQL
libSQL es un fork de SQLite que soporta conexiones remotas. Úsalo cuando necesites una base de datos remota sin Cloudflare D1.
import { libsql } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
}),
}),
],
});
Configuración
| Opción | Tipo | Descripción |
|---|---|---|
url | string | URL de base de datos (libsql://... o file:...) |
authToken | string | Token de autenticación para bases remotas (opcional para local) |
Desarrollo local
Usa un archivo libSQL local durante el desarrollo:
database: libsql({ url: "file:./data.db" });
PostgreSQL
PostgreSQL está soportado para despliegues Node.js que necesitan una base de datos relacional completa.
import { postgres } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: postgres({
connectionString: process.env.DATABASE_URL,
}),
}),
],
});
Configuración
Puedes conectar con un string de conexión o parámetros individuales:
// String de conexión
database: postgres({
connectionString: "postgres://user:password@localhost:5432/emdash",
});
// Parámetros individuales
database: postgres({
host: "localhost",
port: 5432,
database: "emdash",
user: "emdash",
password: process.env.DB_PASSWORD,
ssl: true,
});
| Opción | Tipo | Descripción |
|---|---|---|
connectionString | string | URL de conexión PostgreSQL |
host | string | Host de la base de datos |
port | number | Puerto de la base de datos |
database | string | Nombre de la base de datos |
user | string | Usuario de la base de datos |
password | string | Contraseña de la base de datos |
ssl | boolean | Habilitar SSL |
pool.min | number | Conexiones mínimas del pool (predeterminado 0) |
pool.max | number | Conexiones máximas del pool (predeterminado 10) |
Connection Pooling
El adaptador usa pg.Pool internamente. Ajusta el tamaño del pool según tu despliegue:
database: postgres({
connectionString: process.env.DATABASE_URL,
pool: { min: 2, max: 20 },
});
Hyperdrive
Usa el adaptador hyperdrive() para ejecutar EmDash en Cloudflare Workers respaldado por una base de datos PostgreSQL existente — o compatible con Postgres (ej. PlanetScale Postgres). Hyperdrive agrupa y acelera la conexión a través de la red de Cloudflare; el dialecto PostgreSQL de EmDash ejecuta las consultas.
import { hyperdrive, r2 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: hyperdrive({ binding: "HYPERDRIVE" }),
storage: r2({ binding: "MEDIA" }),
}),
],
});
Requisitos
pg >= 8.16.3instalado en tu sitio (pnpm add pg)compatibility_flags: ["nodejs_compat"]compatibility_date >= "2024-09-23"
Configuración
Crea la configuración Hyperdrive y añade el binding a tu configuración Wrangler:
wrangler hyperdrive create emdash-db \
--connection-string "postgres://user:password@host/db?sslmode=verify-full" \
--caching-disabled
wrangler.jsonc
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "<your-hyperdrive-id>"
}
]
} wrangler.toml
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "<your-hyperdrive-id>" Configuración
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
binding | string | "HYPERDRIVE" | Binding Hyperdrive primario (caché deshabilitada) |
cachedBinding | string | — | Binding opcional con caché habilitada para lecturas anónimas |
max | number | 5 | Tamaño máximo del pool de conexiones in-Worker a Hyperdrive |
Servir lecturas anónimas desde caché
Por defecto deshabilitas el caché de Hyperdrive completamente, porque el admin y las escrituras necesitan consistencia read-after-write. Pero las lecturas públicas anónimas — sin sesión, sin escritura — pueden tolerar una corta ventana de desactualización. Si ese compromiso es aceptable, ejecuta dos configuraciones Hyperdrive sobre la misma base de datos: una con caché desactivada (el binding primario) y una con caché activada (cachedBinding). EmDash entonces enruta solicitudes de lectura anónimas a través del binding con caché mientras cada solicitud autenticada y cada escritura permanece en el primario sin caché, preservando la consistencia read-after-write.
# Primario — caché DESACTIVADA (usada por admin, solicitudes auth., escrituras, migraciones)
wrangler hyperdrive create emdash-db \
--connection-string "postgres://user:password@host/db?sslmode=verify-full" \
--caching-disabled
# Con caché — MISMO string de conexión, caché ACTIVADA (solo lecturas anónimas)
wrangler hyperdrive create emdash-db-cached \
--connection-string "postgres://user:password@host/db?sslmode=verify-full"
{
"hyperdrive": [
{ "binding": "HYPERDRIVE", "id": "<caching-disabled-id>" },
{ "binding": "HYPERDRIVE_CACHED", "id": "<caching-enabled-id>" }
]
}
database: hyperdrive({ binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" });
Este es el patrón de dos configuraciones que Cloudflare documenta para caché. EmDash decide qué binding usar por solicitud:
- Lecturas anónimas de rutas del sitio público (
GET/HEAD, sin sesión, no bajo/_emdash) →cachedBindingcon caché. - Solicitudes autenticadas (editores, autores) →
bindingsin caché. - Escrituras (
POST,PUT,DELETE, incluyendo anónimas) →bindingsin caché. - Cualquier solicitud bajo
/_emdash(admin, setup, auth, APIs internas), incluso unGETanónimo →bindingsin caché. - Migraciones y arranque en frío → siempre el
bindingprimario.
SQLite
SQLite con better-sqlite3 es la opción más simple para despliegues Node.js.
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
}),
],
});
Configuración
| Opción | Tipo | Descripción |
|---|---|---|
url | string | Ruta de archivo con prefijo file: |
Ruta de archivo
La url debe comenzar con file::
// Ruta relativa
database: sqlite({ url: "file:./data/emdash.db" });
// Ruta absoluta
database: sqlite({ url: "file:/var/data/emdash.db" });
// Desde variable de entorno
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });
Migraciones
EmDash ejecuta migraciones automáticamente en la primera solicitud, para cada dialecto soportado (D1, SQLite, libSQL, PostgreSQL). Las migraciones están empaquetadas con el paquete emdash e integradas en tu build.
Si la base de datos está vacía (sin colecciones) y el asistente de configuración no se ha completado, EmDash también aplica un archivo seed en el primer arranque. El seed se lee de .emdash/seed.json, la ruta en package.json#emdash.seed, o seed/seed.json — el primero encontrado — y se integra en el build en tiempo de compilación. Si ninguno está presente, se usa un seed predeterminado integrado. Los arranques posteriores contra una base de datos existente dejan su contenido intacto.
Configuración basada en entorno
Usa diferentes bases de datos por entorno:
import { sqlite, libsql, postgres } from "emdash/db";
import { d1 } from "@emdash-cms/cloudflare";
const database = import.meta.env.PROD ? d1({ binding: "DB" }) : sqlite({ url: "file:./data.db" });
export default defineConfig({
integrations: [emdash({ database })],
});
La elección también puede basarse en una variable de entorno en vez del modo de build:
const database = process.env.DATABASE_URL
? postgres({ connectionString: process.env.DATABASE_URL })
: sqlite({ url: "file:./data.db" });