Orange Book
External databases

Connect Turso from Workers: @libsql/client/web is the only path

Turso is libSQL (a SQLite fork) and cannot use Hyperdrive; in Workers you must import from @libsql/client/web.

Edited and verified by Orange Book Editorial Team ·

INTEGRATIONSINTERMEDIATE25 minutesVerified 2026-08-27

Bottom line first

Turso is built on libSQL, and Hyperdrive's supported-database list does not include SQLite/libSQL, so Hyperdrive is not an option. The only path is the official @libsql/client, and inside Workers you must import explicitly from @libsql/client/web.

Why there is only one path

Hyperdrive pools the Postgres/MySQL TCP protocols; libSQL is outside its supported scope. Fortunately @libsql/client in HTTP mode fits Workers naturally: every request is a single HTTPS call, with no long-lived connection required.

The free tier covers roughly 100 databases and 5GB of storage — enough for prototypes and small-to-medium applications.

Prepare the database and credentials

turso db create notes
turso db show notes --url        # shaped like libsql://<db>-<user>.turso.io
turso db tokens create notes     # generates an auth token

Store the connection string and the token as separate secrets:

npx wrangler secret put TURSO_DATABASE_URL
npx wrangler secret put TURSO_AUTH_TOKEN

Do not put the token into vars in wrangler.jsonc, and never commit it. If it leaks, regenerate and rotate it on the Turso side.

Worker code

npm i @libsql/client

The import path decides whether it runs

A plain import { createClient } from '@libsql/client' does not work in the Workers runtime — it resolves to a build that depends on Node native modules. You must write @libsql/client/web.

src/index.ts
import { createClient } from '@libsql/client/web';

interface Env {
  TURSO_DATABASE_URL: string;
  TURSO_AUTH_TOKEN: string;
}

export default {
  async fetch(request, env: Env): Promise<Response> {
    const client = createClient({
      url: env.TURSO_DATABASE_URL,
      authToken: env.TURSO_AUTH_TOKEN,
    });
    try {
      const result = await client.execute('SELECT id, title FROM notes LIMIT 10');
      return Response.json({ notes: result.rows });
    } catch (error) {
      return Response.json({ error: String(error) }, { status: 502 });
    }
  },
};

This path needs no Wrangler binding; the only configuration is the two secrets.

Verification and troubleshooting

curl -s https://<worker>.workers.dev/notes
SymptomCheck firstRecovery
Build or runtime errors about missing Node modulesWhether the import path is @libsql/client/webFix the import and redeploy
401/403Whether the token is mistyped, rotated, or belongs to another databaseRecreate it with turso db tokens create and update via wrangler secret put
Protocol errors on the URLWhether the URL starts with libsql:// rather than https://Use the raw value from turso db show --url
Slow queries with no improvementWhether you expected Hyperdrive poolinglibSQL does not support Hyperdrive; add application-layer caching such as the Cache API

Remote boundary and rollback

Creating the Turso database, generating tokens, writing secrets, and deploying the Worker all change remote state; this tutorial does not run those actions. Rollback: remove the related routes in code and redeploy — Workers holds no long-lived connections, so there is no pool to drain. Then delete the TURSO_DATABASE_URL and TURSO_AUTH_TOKEN secrets in Cloudflare and revoke the token on the Turso side. If you are rolling the whole approach back to D1, export the data first, then import into D1 and rewrite the data layer against the D1 binding — the schema is SQLite dialect, so migration cost is relatively low, but verify table by table.

Next: connect TiDB from Workers. For the selection recap, see the external database integrations overview.

Primary sources

Did this page help you complete your goal?

Beta feedback is generated in this browser and is never uploaded automatically.

On this page