EmDash는 여러 데이터베이스 백엔드를 지원합니다. 배포 대상에 따라 선택하세요.
개요
| 데이터베이스 | 적합한 용도 | 배포 |
|---|---|---|
| D1 | Cloudflare Workers | 엣지, 글로벌 분산 |
| Hyperdrive | Cloudflare Workers의 PostgreSQL | 엣지, 기존 Postgres |
| PostgreSQL | Node.js 프로덕션 | Postgres가 있는 모든 플랫폼 |
| libSQL | 원격 데이터베이스 | 엣지 또는 Node.js |
| SQLite | Node.js, 로컬 개발 | 단일 서버 |
Cloudflare D1
D1은 Cloudflare의 서버리스 SQLite 데이터베이스입니다. Cloudflare Workers에 배포할 때 사용합니다.
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
}),
],
});
구성
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
binding | string | — | wrangler.jsonc의 D1 바인딩 이름 |
session | string | "disabled" | 읽기 복제 모드 (아래 참조) |
bookmarkCookie | string | "__em_d1_bookmark" | 세션 북마크용 쿠키 이름 |
설정
wrangler.jsonc
{
"d1_databases": [
{
"binding": "DB",
"database_name": "emdash-db"
}
]
} wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "emdash-db" 읽기 복제본
D1은 전 세계에 분산된 사이트의 읽기 지연 시간을 줄이기 위해 읽기 복제를 지원합니다. 활성화하면 읽기 쿼리가 항상 기본 데이터베이스를 조회하는 대신 가까운 복제본으로 라우팅됩니다.
EmDash는 D1 Sessions API를 사용하여 이를 투명하게 관리합니다. session 옵션으로 활성화하세요:
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({
binding: "DB",
session: "auto",
}),
}),
],
});
세션 모드
| 모드 | 동작 |
|---|---|
"disabled" | 세션 없음. 모든 쿼리가 기본으로 이동. 기본값. |
"auto" | 익명 요청은 가장 가까운 복제본에서 읽기. 인증된 사용자는 북마크 쿠키를 통해 read-your-writes 일관성 확보. |
"primary-first" | "auto"와 동일하나 첫 번째 쿼리는 항상 기본으로. 쓰기가 매우 빈번한 사이트용. |
작동 방식
- 익명 방문자는
first-unconstrained를 받음 — 가장 낮은 지연 시간을 위해 가장 가까운 복제본에서 읽기. 익명 사용자는 쓰기를 하지 않으므로 일관성 보장이 불필요. - 인증된 사용자 (편집자, 저자)는 북마크 기반 세션을 받음. 쓰기 후 북마크 쿠키가 다음 요청이 최소한 해당 상태를 보도록 보장.
- 쓰기 요청 (
POST,PUT,DELETE)은 항상 기본 데이터베이스에서 시작. - 빌드 시 쿼리 (Astro 콘텐츠 컬렉션)는 세션을 완전히 우회하고 기본을 직접 사용.
libSQL
libSQL은 원격 연결을 지원하는 SQLite 포크입니다. 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,
}),
}),
],
});
구성
| 옵션 | 타입 | 설명 |
|---|---|---|
url | string | 데이터베이스 URL (libsql://... 또는 file:...) |
authToken | string | 원격 데이터베이스 인증 토큰 (로컬에서는 선택사항) |
로컬 개발
개발 중에는 로컬 libSQL 파일을 사용:
database: libsql({ url: "file:./data.db" });
PostgreSQL
PostgreSQL은 완전한 관계형 데이터베이스가 필요한 Node.js 배포에서 지원됩니다.
import { postgres } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: postgres({
connectionString: process.env.DATABASE_URL,
}),
}),
],
});
구성
연결 문자열 또는 개별 매개변수로 연결할 수 있습니다:
// 연결 문자열
database: postgres({
connectionString: "postgres://user:password@localhost:5432/emdash",
});
// 개별 매개변수
database: postgres({
host: "localhost",
port: 5432,
database: "emdash",
user: "emdash",
password: process.env.DB_PASSWORD,
ssl: true,
});
| 옵션 | 타입 | 설명 |
|---|---|---|
connectionString | string | PostgreSQL 연결 URL |
host | string | 데이터베이스 호스트 |
port | number | 데이터베이스 포트 |
database | string | 데이터베이스 이름 |
user | string | 데이터베이스 사용자 |
password | string | 데이터베이스 비밀번호 |
ssl | boolean | SSL 활성화 |
pool.min | number | 풀 최소 연결 수 (기본값 0) |
pool.max | number | 풀 최대 연결 수 (기본값 10) |
커넥션 풀링
어댑터는 내부적으로 pg.Pool을 사용합니다. 배포에 맞게 풀 크기를 조정하세요:
database: postgres({
connectionString: process.env.DATABASE_URL,
pool: { min: 2, max: 20 },
});
Hyperdrive
hyperdrive() 어댑터를 사용하여 기존 PostgreSQL — 또는 Postgres 호환 (예: PlanetScale Postgres) — 데이터베이스로 Cloudflare Workers에서 EmDash를 실행합니다. Hyperdrive는 Cloudflare 네트워크를 통해 연결을 풀링하고 가속합니다. EmDash의 PostgreSQL 다이얼렉트가 쿼리를 실행합니다.
import { hyperdrive, r2 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: hyperdrive({ binding: "HYPERDRIVE" }),
storage: r2({ binding: "MEDIA" }),
}),
],
});
요구사항
- 사이트에
pg >= 8.16.3설치 (pnpm add pg) compatibility_flags: ["nodejs_compat"]compatibility_date >= "2024-09-23"
설정
Hyperdrive 구성을 생성하고 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>" 구성
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
binding | string | "HYPERDRIVE" | 기본 (캐싱 비활성화) Hyperdrive 바인딩 |
cachedBinding | string | — | 익명 읽기용 캐싱 활성화 선택적 바인딩 |
max | number | 5 | Hyperdrive에 대한 인워커 커넥션 풀 최대 크기 |
익명 읽기를 캐시에서 제공
기본적으로 관리자와 쓰기가 read-after-write 일관성을 필요로 하므로 Hyperdrive 캐싱을 완전히 비활성화합니다. 그러나 익명 공개 읽기 — 세션 없음, 쓰기 없음 — 는 짧은 오래된 데이터 창을 허용할 수 있습니다. 이 트레이드오프가 허용 가능하면 동일 데이터베이스에 두 개의 Hyperdrive 구성을 실행합니다: 하나는 캐싱 비활성화 (기본 binding), 다른 하나는 캐싱 활성화 (cachedBinding). EmDash는 익명 읽기 요청을 캐시 활성화 바인딩으로 라우팅하고 모든 인증된 요청과 쓰기는 캐시 없는 기본에 유지하여 read-after-write 일관성을 보존합니다.
# 기본 — 캐시 비활성화 (관리, 인증 요청, 쓰기, 마이그레이션용)
wrangler hyperdrive create emdash-db \
--connection-string "postgres://user:password@host/db?sslmode=verify-full" \
--caching-disabled
# 캐시 활성화 — 동일 연결 문자열, 캐시 활성화 (익명 읽기 전용)
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" });
이것은 Cloudflare가 캐싱을 위해 문서화한 두 구성 패턴입니다. EmDash는 요청별로 어떤 바인딩을 사용할지 결정합니다:
- 공개 사이트 경로의 익명 읽기 (
GET/HEAD, 세션 없음,/_emdash하위 아님) → 캐시 활성화cachedBinding. - 인증된 요청 (편집자, 저자) → 캐시 없는
binding. - 쓰기 (
POST,PUT,DELETE, 익명 포함) → 캐시 없는binding. /_emdash하위의 모든 요청 (관리, 설정, 인증, 내부 API), 익명GET포함 → 캐시 없는binding.- 마이그레이션 및 콜드 스타트 → 항상 기본
binding.
SQLite
better-sqlite3를 사용하는 SQLite는 Node.js 배포를 위한 가장 간단한 옵션입니다.
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
}),
],
});
구성
| 옵션 | 타입 | 설명 |
|---|---|---|
url | string | file: 접두사가 있는 파일 경로 |
파일 경로
url은 file:로 시작해야 합니다:
// 상대 경로
database: sqlite({ url: "file:./data/emdash.db" });
// 절대 경로
database: sqlite({ url: "file:/var/data/emdash.db" });
// 환경 변수에서
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });
마이그레이션
EmDash는 지원되는 모든 다이얼렉트 (D1, SQLite, libSQL, PostgreSQL)에서 첫 번째 요청 시 자동으로 마이그레이션을 실행합니다. 마이그레이션은 emdash 패키지에 번들되어 빌드에 임베드됩니다.
데이터베이스가 비어 있고 (컬렉션 없음) 설정 마법사가 완료되지 않은 경우, EmDash는 첫 시작 시 시드 파일도 적용합니다. 시드는 .emdash/seed.json, package.json#emdash.seed의 경로, 또는 seed/seed.json에서 읽습니다 — 먼저 찾은 것 — 그리고 컴파일 시 빌드에 포함됩니다. 없으면 내장 기본 시드가 사용됩니다. 기존 데이터베이스에 대한 이후 시작은 내용을 변경하지 않습니다.
환경 기반 구성
환경별로 다른 데이터베이스를 사용:
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 })],
});
빌드 모드 대신 환경 변수를 기반으로 선택할 수도 있습니다:
const database = process.env.DATABASE_URL
? postgres({ connectionString: process.env.DATABASE_URL })
: sqlite({ url: "file:./data.db" });