Skip to content

Connect to and query your Turso database using Workers

Last reviewed: over 1 year ago

This tutorial will guide you on how to build globally distributed applications with Cloudflare Workers, and Turso, an edge-hosted distributed database based on libSQL. By using Workers and Turso, you can create applications that are close to your end users without having to maintain or operate infrastructure in tens or hundreds of regions.

Prerequisites

Before continuing with this tutorial, you should have:

  • Successfully created up your first Cloudflare Worker and/or have deployed a Cloudflare Worker before.
  • Installed Wrangler, a command-line tool for building Cloudflare Workers.
  • A GitHub account, required for authenticating to Turso.
  • A basic familiarity with installing and using command-line interface (CLI) applications.

Install the Turso CLI

You will need the Turso CLI to create and populate a database. Run either of the following two commands in your terminal to install the Turso CLI:

Terminal window
# On macOS or Linux with Homebrew
brew install chiselstrike/tap/turso
# Manual scripted installation
curl -sSfL <https://get.tur.so/install.sh> | bash

After you have installed the Turso CLI, verify that the CLI is in your shell path:

Terminal window
turso --version
# This should output your current Turso CLI version (your installed version may be higher):
turso version v0.51.0

Create and populate a database

Before you create your first Turso database, you need to log in to the CLI using your GitHub account by running:

Terminal window
turso auth login
Waiting for authentication...
Success! Logged in as <your GitHub username>

turso auth login will open a browser window and ask you to sign into your GitHub account, if you are not already logged in. The first time you do this, you will need to give the Turso application permission to use your account. Select Approve to grant Turso the permissions needed.

After you have authenticated, you can create a database by running turso db create <DATABASE_NAME>. Turso will automatically choose a location closest to you.

Terminal window
turso db create my-db
# Example:
[===> ]
Creating database my-db in Los Angeles, California (US) (lax)
# Once succeeded:
Created database my-db in Los Angeles, California (US) (lax) in 34 seconds.

With your first database created, you can now connect to it directly and execute SQL against it:

Terminal window
turso db shell my-db

To get started with your database, create and define a schema for your first table. In this example, you will create a example_users table with one column: email (of type text) and then populate it with one email address.

In the shell you just opened, paste in the following SQL:

create table example_users (email text);
insert into example_users values ("foo@bar.com");

If the SQL statements succeeded, there will be no output. Note that the trailing semi-colons (;) are necessary to terminate each SQL statement.

Type .quit to exit the shell.

Use Wrangler to create a Workers project

The Workers command-line interface, Wrangler, allows you to create, locally develop, and deploy your Workers projects.

To create a new Workers project (named worker-turso-ts), run the following:

Terminal window
npm create cloudflare@latest -- worker-turso-ts

For setup, select the following options:

  • For What would you like to start with?, choose Hello World example.
  • For Which template would you like to use?, choose Hello World Worker.
  • For Which language do you want to use?, choose TypeScript.
  • For Do you want to use git for version control?, choose Yes.
  • For Do you want to deploy your application?, choose No (we will be making some changes before deploying).

To start developing your Worker, cd into your new project directory:

Terminal window
cd worker-turso-ts

In your project directory, you now have the following files:

  • wrangler.toml: Your Wrangler configuration file.
  • src/index.ts: A minimal Hello World Worker written in TypeScript
  • package.json: A minimal Node dependencies configuration file.
  • tsconfig.json: TypeScript configuration that includes Workers types. Only generated if indicated.

For this tutorial, only the wrangler.toml and src/index.ts files are relevant. You will not need to edit the other files, and they should be left as is.

Configure your Worker for your Turso database

The Turso client library requires two pieces of information to make a connection:

  1. LIBSQL_DB_URL - The connection string for your Turso database.
  2. LIBSQL_DB_AUTH_TOKEN - The authentication token for your Turso database. This should be kept a secret, and not committed to source code.

To get the URL for your database, run the following Turso CLI command, and copy the result:

Terminal window
turso db show my-db --url
libsql://my-db-<your-github-username>.turso.io

Open wrangler.toml in your editor and at the bottom of the file, create a new [vars] section representing the environment variables for your project:

[vars]
LIBSQL_DB_URL = "paste-your-url-here"

Save the changes to wrangler.toml.

Next, create a long-lived authentication token for your Worker to use when connecting to your database. Run the following Turso CLI command, and copy the output to your clipboard:

Terminal window
turso db tokens create my-db -e none
# Will output a long text string (an encoded JSON Web Token)

To keep this token secret:

  1. You will create a .dev.vars file for local development. Do not commit this file to source control. You should add .dev.vars to your .gitignore` file if you are using Git.
  • You will also create a secret to keep your authentication token confidential.

First, create a new file called .dev.vars with the following structure. Paste your authentication token in the quotation marks:

LIBSQL_DB_AUTH_TOKEN="<YOUR_AUTH_TOKEN>"

Save your changes to .dev.vars. Next, store the authentication token as a secret for your production Worker to reference. Run the following wrangler secret command to create a Secret with your token:

Terminal window
# Ensure you specify the secret name exactly: your Worker will need to reference it later.
npx wrangler secret put LIBSQL_DB_AUTH_TOKEN
? Enter a secret value: › <paste your token here>

Select <Enter> on your keyboard to save the token as a secret. Both LIBSQL_DB_URL and LIBSQL_DB_AUTH_TOKEN will be available in your Worker’s environment at runtime.

Install extra libraries

Install the Turso client library and a router:

Terminal window
npm install @libsql/client itty-router

The @libsql/client library allows you to query a Turso database. The itty-router library is a lightweight router you will use to help handle incoming requests to the worker.

Write your Worker

You will now write a Worker that will:

  1. Handle an HTTP request.
  2. Route it to a specific handler to either list all users in our database or add a new user.
  3. Return the results and/or success.

Open src/index.ts and delete the existing template. Copy the below code exactly as is and paste it into the file:

import { Client as LibsqlClient, createClient } from "@libsql/client/web";
import { Router, RouterType } from "itty-router";
export interface Env {
// The environment variable containing your the URL for your Turso database.
LIBSQL_DB_URL?: string;
// The Secret that contains the authentication token for your Turso database.
LIBSQL_DB_AUTH_TOKEN?: string;
// These objects are created before first use, then stashed here
// for future use
router?: RouterType;
}
export default {
async fetch(request, env): Promise<Response> {
if (env.router === undefined) {
env.router = buildRouter(env);
}
return env.router.fetch(request);
},
} satisfies ExportedHandler<Env>;
function buildLibsqlClient(env: Env): LibsqlClient {
const url = env.LIBSQL_DB_URL?.trim();
if (url === undefined) {
throw new Error("LIBSQL_DB_URL env var is not defined");
}
const authToken = env.LIBSQL_DB_AUTH_TOKEN?.trim();
if (authToken === undefined) {
throw new Error("LIBSQL_DB_AUTH_TOKEN env var is not defined");
}
return createClient({ url, authToken });
}
function buildRouter(env: Env): RouterType {
const router = Router();
router.get("/users", async () => {
const client = buildLibsqlClient(env);
const rs = await client.execute("select * from example_users");
return Response.json(rs);
});
router.get("/add-user", async (request) => {
const client = buildLibsqlClient(env);
const email = request.query.email;
if (email === undefined) {
return new Response("Missing email", { status: 400 });
}
if (typeof email !== "string") {
return new Response("email must be a single string", { status: 400 });
}
if (email.length === 0) {
return new Response("email length must be > 0", { status: 400 });
}
try {
await client.execute({
sql: "insert into example_users values (?)",
args: [email],
});
} catch (e) {
console.error(e);
return new Response("database insert failed");
}
return new Response("Added");
});
router.all("*", () => new Response("Not Found.", { status: 404 }));
return router;
}

Save your src/index.ts file with your changes.

Note:

  • The libSQL client library import ‘@libsql/client/web’ must be imported exactly as shown when working with Cloudflare workers. The non-web import will not work in the Workers environment.
  • The Env interface contains the environment variable and secret you defined earlier.
  • The Env interface also caches the libSQL client object and router, which are created on the first request to the Worker.
  • The /users route fetches all rows from the example_users table you created in the Turso shell. It simply serializes the ResultSet object as JSON directly to the caller.
  • The /add-user route inserts a new row using a value provided in the query string.

With your environment configured and your code ready, you will now test your Worker locally before you deploy.

Run the Worker locally with Wrangler

To run a local instance of our Worker (entirely on your machine), run the following command:

Terminal window
npx wrangler dev

You should be able to review output similar to the following:

Your worker has access to the following bindings:
- Vars:
- LIBSQL_DB_URL: "your-url"
⎔ Starting a local server...
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Debugger listening on ws://127.0.0.1:61918/1064babd-bc9d-4bed-b171-b35dab3b7680
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
[mf:inf] Worker reloaded! (40.25KiB)
[mf:inf] Listening on 0.0.0.0:8787
[mf:inf] - http://127.0.0.1:8787
[mf:inf] - http://192.168.1.136:8787
[mf:inf] Updated `Request.cf` object cache!

The localhost address — the one with 127.0.0.1 in it — is a web-server running locally on your machine.

Connect to it and validate your Worker returns the email address you inserted when you created your example_users table by visiting the /users route in your browser: http://127.0.0.1:8787/users.

You should see JSON similar to the following containing the data from the example_users table:

{
"columns": ["email"],
"rows": [{ "email": "foo@bar.com" }],
"rowsAffected": 0
}

Test the /add-users route and pass it an email address to insert: http://127.0.0.1:8787/add-user?email=test@test.com

You should see the text “Added”. If you load the first URL with the /users route again (http://127.0.0.1:8787/users), it will show the newly added row. You can repeat this as many times as you like. Note that due to its design, your application will not stop you from adding duplicate email addresses.

Quit Wrangler by typing q into the shell where it was started.

Deploy to Cloudflare

After you have validated that your Worker can connect to your Turso database, deploy your Worker. Run the following Wrangler command to deploy your Worker to the Cloudflare global network:

Terminal window
npx wrangler deploy

The first time you run this command, it will launch a browser, ask you to sign in with your Cloudflare account, and grant permissions to Wrangler.

The deploy command will output the following:

Your worker has access to the following bindings:
- Vars:
- LIBSQL_DB_URL: "your-url"
...
Published worker-turso-ts (0.19 sec)
https://worker-turso-ts.<your-Workers-subdomain>.workers.dev
Current Deployment ID: f9e6b48f-5aac-40bd-8f44-8a40be2212ff

You have now deployed a Worker that can connect to your Turso database, query it, and insert new data.

Optional: Clean up

To clean up the resources you created as part of this tutorial:

  • If you do not want to keep this Worker, run npx wrangler delete worker-turso-ts to delete the deployed Worker.
  • You can also delete your Turso database via turso db destroy my-db.