O EmDash suporta vários backends de banco de dados. Escolha com base no seu alvo de deploy.
Visão geral
| Banco de dados | Ideal para | Deploy |
|---|---|---|
| D1 | Cloudflare Workers | Edge, distribuído globalmente |
| Hyperdrive | PostgreSQL no Cloudflare Workers | Edge, Postgres existente |
| PostgreSQL | Produção Node.js | Qualquer plataforma com Postgres |
| libSQL | Bancos de dados remotos | Edge ou Node.js |
| SQLite | Node.js, desenvolvimento local | Servidor único |
Cloudflare D1
D1 é o banco de dados SQLite serverless da Cloudflare. Use ao fazer deploy no Cloudflare Workers.
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
}),
],
});
Configuração
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
binding | string | — | Nome do binding D1 do wrangler.jsonc |
session | string | "disabled" | Modo de replicação de leitura (veja abaixo) |
bookmarkCookie | string | "__em_d1_bookmark" | Nome do cookie para bookmarks de sessão |
Setup
wrangler.jsonc
{
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-db"
}
]
} wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "emdash-db" Read Replicas
O D1 suporta replicação de leitura para reduzir a latência de leitura em sites distribuídos globalmente. Quando habilitada, as consultas de leitura são roteadas para réplicas próximas em vez de sempre consultar o banco de dados primário.
O EmDash usa a API D1 Sessions para gerenciar isso de forma transparente. Habilite com a opção session:
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({
binding: "DB",
session: "auto",
}),
}),
],
});
Modos de sessão
| Modo | Comportamento |
|---|---|
"disabled" | Sem sessões. Todas as consultas vão para o primário. Padrão. |
"auto" | Requisições anônimas leem da réplica mais próxima. Usuários autenticados obtêm consistência read-your-writes via cookies de bookmark. |
"primary-first" | Como "auto", mas a primeira consulta sempre vai para o primário. Para sites com escritas muito frequentes. |
Como funciona
- Visitantes anônimos obtêm
first-unconstrained— leituras vão para a réplica mais próxima para menor latência. Como usuários anônimos nunca escrevem, não precisam de garantias de consistência. - Usuários autenticados (editores, autores) obtêm sessões baseadas em bookmark. Após uma escrita, um cookie de bookmark garante que a próxima requisição veja pelo menos aquele estado.
- Requisições de escrita (
POST,PUT,DELETE) sempre começam no banco de dados primário. - Consultas em tempo de build (Astro content collections) contornam sessões completamente e usam diretamente o primário.
libSQL
libSQL é um fork do SQLite que suporta conexões remotas. Use quando precisar de um banco de dados remoto sem 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,
}),
}),
],
});
Configuração
| Opção | Tipo | Descrição |
|---|---|---|
url | string | URL do banco de dados (libsql://... ou file:...) |
authToken | string | Token de autenticação para bancos remotos (opcional localmente) |
Desenvolvimento local
Use um arquivo libSQL local durante o desenvolvimento:
database: libsql({ url: "file:./data.db" });
PostgreSQL
PostgreSQL é suportado para deploys Node.js que necessitam de um banco de dados relacional completo.
import { postgres } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: postgres({
connectionString: process.env.DATABASE_URL,
}),
}),
],
});
Configuração
Você pode conectar com uma string de conexão ou parâmetros individuais:
// String de conexão
database: postgres({
connectionString: "postgres://user:password@localhost:5432/emdash",
});
// Parâmetros individuais
database: postgres({
host: "localhost",
port: 5432,
database: "emdash",
user: "emdash",
password: process.env.DB_PASSWORD,
ssl: true,
});
| Opção | Tipo | Descrição |
|---|---|---|
connectionString | string | URL de conexão PostgreSQL |
host | string | Host do banco de dados |
port | number | Porta do banco de dados |
database | string | Nome do banco de dados |
user | string | Usuário do banco de dados |
password | string | Senha do banco de dados |
ssl | boolean | Habilitar SSL |
pool.min | number | Conexões mínimas do pool (padrão 0) |
pool.max | number | Conexões máximas do pool (padrão 10) |
Pool de conexões
O adaptador usa pg.Pool internamente. Ajuste o tamanho do pool baseado no seu deploy:
database: postgres({
connectionString: process.env.DATABASE_URL,
pool: { min: 2, max: 20 },
});
Hyperdrive
Use o adaptador hyperdrive() para executar o EmDash no Cloudflare Workers com um banco de dados PostgreSQL existente — ou compatível com Postgres (ex. PlanetScale Postgres). O Hyperdrive faz pool e acelera a conexão pela rede Cloudflare; o dialeto PostgreSQL do EmDash executa as 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 no seu site (pnpm add pg)compatibility_flags: ["nodejs_compat"]compatibility_date >= "2024-09-23"
Setup
Crie a configuração Hyperdrive e adicione o binding à sua configuração 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>" Configuração
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
binding | string | "HYPERDRIVE" | Binding Hyperdrive primário (cache desabilitado) |
cachedBinding | string | — | Binding opcional com cache habilitado para leituras anônimas |
max | number | 5 | Tamanho máximo do pool de conexões in-Worker para o Hyperdrive |
Servir leituras anônimas do cache
Por padrão, você desabilita completamente o cache do Hyperdrive porque admin e escritas precisam de consistência read-after-write. Mas leituras públicas anônimas — sem sessão, sem escrita — podem tolerar uma janela curta de dados obsoletos. Se esse tradeoff é aceitável, execute duas configurações Hyperdrive sobre o mesmo banco de dados: uma com cache desabilitado (o binding primário) e uma com cache habilitado (cachedBinding). O EmDash roteia as requisições de leitura anônimas pelo binding com cache enquanto todas as requisições autenticadas e escritas permanecem no primário sem cache, preservando a consistência read-after-write.
# Primário — cache DESABILITADO (admin, requisições auth., escritas, migrações)
wrangler hyperdrive create emdash-db \
--connection-string "postgres://user:password@host/db?sslmode=verify-full" \
--caching-disabled
# Com cache — MESMA string de conexão, cache HABILITADO (apenas leituras 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 é o padrão de duas configurações que a Cloudflare documenta para cache. O EmDash decide qual binding usar por requisição:
- Leituras anônimas dos caminhos do site público (
GET/HEAD, sem sessão, não sob/_emdash) →cachedBindingcom cache. - Requisições autenticadas (editores, autores) →
bindingsem cache. - Escritas (
POST,PUT,DELETE, incluindo anônimas) →bindingsem cache. - Qualquer requisição sob
/_emdash(admin, setup, auth, APIs internas), mesmo umGETanônimo →bindingsem cache. - Migrações e cold start → sempre o
bindingprimário.
SQLite
SQLite com better-sqlite3 é a opção mais simples para deploys Node.js.
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
}),
],
});
Configuração
| Opção | Tipo | Descrição |
|---|---|---|
url | string | Caminho do arquivo com prefixo file: |
Caminho do arquivo
A url deve começar com file::
// Caminho relativo
database: sqlite({ url: "file:./data/emdash.db" });
// Caminho absoluto
database: sqlite({ url: "file:/var/data/emdash.db" });
// De variável de ambiente
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });
Migrações
O EmDash executa migrações automaticamente na primeira requisição, para cada dialeto suportado (D1, SQLite, libSQL, PostgreSQL). As migrações estão empacotadas no pacote emdash e embutidas no seu build.
Se o banco de dados está vazio (sem collections) e o assistente de setup não foi completado, o EmDash também aplica um arquivo seed na primeira inicialização. O seed é lido de .emdash/seed.json, do caminho em package.json#emdash.seed, ou de seed/seed.json — o primeiro encontrado — e embutido no build em tempo de compilação. Se nenhum estiver presente, um seed padrão embutido é usado. Inicializações subsequentes contra um banco de dados existente deixam seu conteúdo intacto.
Configuração baseada em ambiente
Use bancos de dados diferentes por ambiente:
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 })],
});
A escolha também pode ser baseada em variável de ambiente em vez do modo de build:
const database = process.env.DATABASE_URL
? postgres({ connectionString: process.env.DATABASE_URL })
: sqlite({ url: "file:./data.db" });