Search docs

Jump between documentation pages.

Use Turso (libSQL) with DaloyJS

Turso is a distributed database built on libSQL (a fork of SQLite). The @libsql/client driver speaks HTTP and WebSocket, so the same DaloyJS app works on Node, Bun, Deno, Cloudflare Workers, and Vercel Edge.

1. Provision

Create a database via the Turso CLI or dashboard, then grab the URL and auth token. Set them as TURSO_DATABASE_URL and TURSO_AUTH_TOKEN.

2. Install

ts
pnpm add @libsql/client

3. Create a Turso plugin

ts
// src/db/turso.ts
import { createClient, type Client } from "@libsql/client";
import type { App } from "@daloyjs/core";

export const db: Client = createClient({
  url: process.env.TURSO_DATABASE_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN,
});

export const tursoPlugin = {
  name: "turso",
  async register(app: App) {
    app.decorate("db", db);
    app.onClose(async () => {
      db.close();
    });
  },
};

4. Augment app state

ts
// src/types/state.d.ts
import type { Client } from "@libsql/client";

declare module "@daloyjs/core" {
  interface AppState {
    db: Client;
  }
}

5. Use it in a route

ts
import { z } from "zod";
import { App, secureHeaders } from "@daloyjs/core";
import { tursoPlugin } from "./db/turso";

const app = new App();
app.use(secureHeaders());
app.register(tursoPlugin);

const TodoSchema = z.object({ id: z.number(), title: z.string(), done: z.boolean() });

app.route({
  method: "GET",
  path: "/todos",
  operationId: "listTodos",
  responses: { 200: { description: "ok", body: z.array(TodoSchema) } },
  handler: async ({ state }) => {
    const result = await state.db.execute("select id, title, done from todos");
    const rows = result.rows.map((r) => ({
      id: Number(r.id),
      title: String(r.title),
      done: Boolean(r.done),
    }));
    return { status: 200, body: rows };
  },
});

Embedded replicas (Node, Bun)

For ultra-low-latency reads, use an embedded replica that syncs with the primary in the background. Writes still go to the primary; reads are local.

ts
import { createClient } from "@libsql/client";

export const db = createClient({
  url: "file:local.db",
  syncUrl: process.env.TURSO_DATABASE_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN,
  syncInterval: 60,
});

Cloudflare Workers / Vercel Edge

Use the standard HTTP client (no embedded replicas in Workers). Pass env.TURSO_DATABASE_URL instead of process.env.

With Drizzle ORM

ts
pnpm add drizzle-orm
// src/db/drizzle.ts
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,
});
export const db = drizzle({ client });

With Prisma

Prisma supports Turso through the libSQL Driver Adapter in preview. Use Drizzle if you want a stable, production-ready setup today.

See also Cloudflare D1for a SQLite-style option that's bundled into Workers, or the database hosting overview.