Prerequisites

Before you start, make sure you:

1

Retrieve database credentials

You will need an existing database to continue. If you don’t have one, create one.

Get the database URL:

turso db show --url <database-name>

Get the database authentication token:

turso db tokens create <database-name>

Assign credentials to the environment variables inside .env.

TURSO_DATABASE_URL=
TURSO_AUTH_TOKEN=
You will want to store these as environment variables.
2

Add the libsql crate to the project

cargo add libsql

Optionally, you can add a package such as dotenvy to help you work with .env files:

cargo add dotenvy
3

Execute SQL

use libsql::{Builder, Connection, Database, Result};

#[tokio::main]
async fn main() -> Result<()> {
    dotenv().ok();

    let db_url = std::env::var("TURSO_DATABASE_URL").expect("TURSO_DATABASE_URL must be set");
    let auth_token = std::env::var("TURSO_AUTH_TOKEN").expect("TURSO_AUTH_TOKEN must be set");

    let db = Builder::new_remote(db_url, auth_token)
        .build()
        .await?;

    let conn = db.connect()?;

    // Execute a query
    let mut rows = conn.query("SELECT * FROM users", ()).await?;

    while let Some(row) = rows.next().await? {
        let id: i64 = row.get(0)?;
        let name: String = row.get(1)?;
        println!("User: {} - {}", id, name);
    }

    Ok(())
}
4

Use in an Axum handler

use axum::{
    extract::State,
    routing::get,
    Json, Router,
};
use libsql::{Builder, Connection, Database};
use serde::Serialize;

#[derive(Clone)]
struct AppState {
    db: Database,
}

#[derive(Serialize)]
struct User {
    id: i64,
    name: String,
}

async fn get_users(State(state): State<AppState>) -> Json<Vec<User>> {
    let conn = state.db.connect().unwrap();
    let mut rows = conn.query("SELECT id, name FROM users", ()).await.unwrap();

    let mut users = Vec::new();
    while let Some(row) = rows.next().await.unwrap() {
        users.push(User {
            id: row.get(0).unwrap(),
            name: row.get(1).unwrap(),
        });
    }

    Json(users)
}

#[tokio::main]
async fn main() {
    let db_url = std::env::var("TURSO_DATABASE_URL").expect("TURSO_DATABASE_URL must be set");
    let auth_token = std::env::var("TURSO_AUTH_TOKEN").expect("TURSO_AUTH_TOKEN must be set");

    let db = Builder::new_remote(db_url, auth_token)
        .build()
        .await
        .unwrap();

    let app_state = AppState { db };

    let app = Router::new()
        .route("/users", get(get_users))
        .with_state(app_state);

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

This example creates a shared Database instance in the application state, which is then used in the handler to execute queries.