Drizzle + Turso
Drizzle을 Turso와 함께 쓰도록 설정하는 방법이에요. 설치부터 스키마 정의, 마이그레이션, 쿼리, 벡터 임베딩까지 순서대로 따라오세요.
출처: 문서
본문
Drizzle은 Turso 연동에 @libsql/client를 사용해요. 그리고 로컬/임베디드 용도로는 @tursodatabase/database 베타 지원도 있어요.
Prerequisites
시작하기 전에 다음을 확인하세요:
Install Drizzle and the libSQL SDK
npm i drizzle-orm @libsql/client dotenv
npm i -D drizzle-kit
pnpm add drizzle-orm @libsql/client dotenv
pnpm add -D drizzle-kit
yarn add drizzle-orm @libsql/client dotenv
yarn add -D drizzle-kit
마지막으로 package.json에 세 개의 새 scripts를 추가하면 준비 끝이에요:
{
"scripts": {
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
}
}
Retrieve database credentials
데이터베이스 자격 증명(URL과 인증 토큰)을 받아서 환경 변수로 저장해 두세요.
Create a Drizzle schema
import { sql } from "drizzle-orm";
import { text, sqliteTable } from "drizzle-orm/sqlite-core";
export const fooTable = sqliteTable("foo", {
bar: text("bar").notNull().default("Hey!"),
});
Configure Drizzle Kit
프로젝트 루트에 drizzle.config.ts 파일을 다음 내용으로 만드세요:
require("dotenv").config();
import type { Config } from "drizzle-kit";
export default {
schema: "./db/schema.ts",
out: "./migrations",
dialect: "turso",
dbCredentials: {
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
},
} satisfies Config;
참고로, 위에서는 dotenv를 썼지만 Next.js, Remix, Astro, Vite 같은 도구를 쓴다면 내장 환경 변수 관리자로 이 값들을 읽어 올 수 있어요.
Connect Drizzle with libSQL
Node.js / Serverless
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
const turso = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
});
export const db = drizzle(turso);
Edge Runtimes
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client/web";
const turso = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
});
export const db = drizzle(turso);
Database migrations
Drizzle은 drizzle-kit으로 데이터베이스 마이그레이션을 생성하고 적용할 수 있어요.
스키마를 변경할 때마다 db:generate를 실행하세요:
npm run db:generate
이제 db:migrate로 데이터베이스에 변경을 적용하세요:
npm run db:migrate
Query
import { db } from "./db";
import { fooTable } from "./schema";
const result = await db.select().from(fooTable).all();
Connect Drizzle Studio
npm run db:studio
pnpm run db:studio
Vector Embeddings
Drizzle을 확장해서 Turso의 네이티브 벡터를 지원할 수 있어요 — 자세히 보기.
Define custom vector type
db/schema.ts 안에 다음을 추가하세요:
import { sql } from "drizzle-orm";
import { customType } from "drizzle-orm/sqlite-core";
const float32Array = customType<{
data: number[];
config: { dimensions: number };
configRequired: true;
driverData: Buffer;
}>({
dataType(config) {
return `F32_BLOB(${config.dimensions})`;
},
fromDriver(value: Buffer) {
return Array.from(new Float32Array(value.buffer));
},
toDriver(value: number[]) {
return sql`vector32(${JSON.stringify(value)})`;
},
});
Create a table with a vector column
이제 스키마를 정의하는 곳에서 float32Array를 호출해서 벡터를 저장하는 컬럼을 만들어요:
import { sqliteTable, integer } from "drizzle-orm/sqlite-core";
export const vectorTable = sqliteTable("vector_table", {
id: integer("id").primaryKey(),
vector: float32Array("vector", { dimensions: 3 }),
});
Create a vector index
인덱스를 만들 때는 raw SQL을 사용해야 해요:
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN,
});
const db = drizzle(client);
await db.run(sql`
CREATE INDEX IF NOT EXISTS vector_index
ON vector_table(vector)
USING vector_cosine(3)
`);
Insert vector data
await db
.insert(vectorTable)
.values([{ vector: sql`vector32(${JSON.stringify([1.1, 2.2, 3.3])})` }]);
Query vector data
벡터 거리를 계산해요:
const res = await db
.select({
distance: sql<number>`vector_distance_cos(${vectorTable.vector}, vector32(${JSON.stringify([2.2, 3.3, 4.4])}))`,
})
.from(vectorTable);
console.log(res);
효율적인 최근접 이웃 검색도 가능해요:
const topK = await db
.select({
id: sql`id`,
distance: sql`distance`,
})
.from(
sql`vector_top_k('vector_index', vector32(${JSON.stringify([2.2, 3.3, 4.4])}), 5)`,
)
.leftJoin(vectorTable, sql`${vectorTable}.id = id`);
console.log(topK);
효율적인 벡터 연산을 위해 적절한 인덱스를 만들고, 용도에 맞게 벡터 차원을 조정하는 것도 잊지 마세요.
더 알아보기 (Learn more)
- TypeScript SDK 퀵스타트 — SDK 기본 흐름 익히기
- Prisma ORM 연동 — 다른 ORM 선택지 보기
- AI와 임베딩 — Turso 네이티브 벡터 기능 상세
- TypeScript SDK 레퍼런스 — 전체 API 살펴보기