How Turso Language Bindings for Go, JavaScript, Python, Java, and .NET Operate

Turso's language bindings are thin FFI wrappers around a unified Rust sync driver that exposes C-compatible functions, enabling each host language to call the same libSQL protocol implementation while maintaining idiomatic APIs.

The tursodatabase/turso repository provides official client libraries that allow developers to interact with distributed SQLite databases using familiar syntax in their preferred language. Rather than implementing separate network clients for each ecosystem, Turso leverages a shared Rust core compiled to native libraries, which the various language bindings invoke through Foreign Function Interface (FFI) mechanisms. This architecture ensures consistent behavior across Go, JavaScript, Python, Java, and .NET while respecting each platform's performance characteristics and concurrency models.

The Shared Rust Foundation

Core Driver Implementation

All language bindings depend on the Rust crate defined in bindings/rust/src/lib.rs, which exports a C-compatible ABI via extern "C" functions. This crate implements connection pooling, statement preparation, and transaction management. The file bindings/rust/src/sync.rs contains the sync driver logic that communicates with Turso's cloud service over HTTP/2, handling SQLite page updates and replication.

Build and Linking Strategy

The Rust core compiles into a static library (.a) or shared object (.so/.dll) depending on the target language's requirements. The workspace Cargo.toml governs versioning across all bindings, ensuring that updating the Rust driver automatically propagates to every language wrapper.

How Each Language Binding Operates

Go Bindings via CGO

The Go binding resides in bindings/go/ and utilizes CGO to link against the compiled Rust static library. The go.mod file defines the module path, while bindings/go/go-driver-sync.mdx documents the synchronous API. Go methods map directly to C symbols exported by bindings/rust/src/lib.rs, wrapped in idiomatic Go types such as *DB and *Stmt.

JavaScript Bindings (Node and WebAssembly)

JavaScript support spans two runtimes. For Node.js, the binding in bindings/javascript/sync/src/lib.rs compiles to a native addon using N-API (via napi-rs), located in bindings/javascript/sync/packages/native. For browsers, wasm-pack compiles the Rust core to WebAssembly. Both approaches load the compiled module and expose JavaScript-friendly promises, though the underlying Rust driver remains strictly synchronous, with async operations handled in worker threads.

Python Bindings via PyO3

The Python extension uses PyO3 and maturin (or setuptools-rust) to build the Rust crate as a native Python module. Configuration in bindings/python/pyproject.toml defines the build pipeline. Functions like turso.connect directly invoke the Rust connection logic from bindings/rust/src/lib.rs, returning Python objects that wrap the underlying database handles.

Java Bindings via JNI

Java integration uses the Java Native Interface (JNI). The build process generates JNI headers from the C symbols in the Rust core, with Java classes loading the native library via System.loadLibrary("turso"). Documentation in bindings/java/java-driver-sync.mdx outlines how the JVM delegates calls to bindings/rust/src/connection.rs and bindings/rust/src/transaction.rs.

.NET Bindings via P/Invoke

The .NET wrapper employs P/Invoke through DllImport attributes to call the C-ABI exported by the Rust DLL. The C# implementation provides managed wrappers like TursoConnection and TursoCommand that marshal data between .NET types and the native Rust structures, as described in bindings/dotnet/dotnet-driver-sync.mdx.

Working Code Examples

Connecting from Go

package main

import (
	"log"

	"github.com/tursodatabase/turso/bindings/go"
)

func main() {
	// Open a connection to a Turso database (replace <URL> with your libSQL URL)
	db, err := go.Open("libsql://<TOKEN>@<HOST>/<DB>")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Execute a simple query
	row, err := db.QueryRow("SELECT sqlite_version()")
	if err != nil {
		log.Fatal(err)
	}
	var version string
	if err := row.Scan(&version); err != nil {
		log.Fatal(err)
	}
	log.Println("SQLite version:", version)
}

Querying from JavaScript (Node.js)

import { Database } from "turso-sync";

const db = new Database("libsql://<TOKEN>@<HOST>/<DB>");

(async () => {
  const rows = await db.execute("SELECT name FROM sqlite_master WHERE type='table'");
  console.log(rows);
})();

Executing SQL in Python

import turso

# Create a connection (URL includes auth token)

conn = turso.connect("libsql://<TOKEN>@<HOST>/<DB>")
cur = conn.cursor()
cur.execute("SELECT sqlite_version()")
print("SQLite version:", cur.fetchone()[0])
conn.close()

Java and .NET Examples

Java:

import com.turso.Database;

public class Main {
    public static void main(String[] args) throws Exception {
        Database db = new Database("libsql://<TOKEN>@<HOST>/<DB>");
        try (var stmt = db.prepareStatement("SELECT sqlite_version()")) {
            var rs = stmt.executeQuery();
            if (rs.next()) {
                System.out.println("SQLite version: " + rs.getString(1));
            }
        }
        db.close();
    }
}

C# (.NET):

using Turso;

var db = new TursoConnection("libsql://<TOKEN>@<HOST>/<DB>");
db.Open();

using var cmd = db.CreateCommand();
cmd.CommandText = "SELECT sqlite_version()";
var version = cmd.ExecuteScalar()!.ToString();
Console.WriteLine($"SQLite version: {version}");

db.Close();

Summary

  • All Turso language bindings rely on a single Rust core located in bindings/rust/src/lib.rs that exposes a C-compatible ABI for universal interoperability.
  • FFI mechanisms vary by language: Go uses CGO, Python uses PyO3, Java uses JNI, .NET uses P/Invoke, and JavaScript uses N-API or WebAssembly.
  • The Rust driver implements a synchronous, blocking API for libSQL protocol communication; languages requiring async semantics (like JavaScript) handle concurrency through worker threads or promise wrappers.
  • Shared versioning via the workspace Cargo.toml ensures consistent feature parity and bug fixes across Go, JavaScript, Python, Java, and .NET simultaneously.

Frequently Asked Questions

Do the Turso language bindings support async/await patterns?

While the underlying Rust driver in bindings/rust/src/sync.rs operates synchronously, language bindings that target async ecosystems implement wrappers to accommodate non-blocking workflows. JavaScript bindings, for example, run the driver in worker threads and expose Promise-based APIs, whereas Python and Go bindings typically expose synchronous interfaces that can be wrapped in language-specific async constructs.

Why does Turso use Rust for the driver core instead of native implementations?

Turso uses a unified Rust core to eliminate code duplication and ensure protocol consistency across all supported languages. By compiling to a C-compatible library once and exposing it via FFI, the project maintains a single source of truth for connection management, replication logic, and SQL parsing, reducing the maintenance burden across bindings/go/, bindings/python/, and other directories.

How are transactions handled across the different language bindings?

Transactions are managed through the Rust core's transaction API defined in bindings/rust/src/transaction.rs, which all bindings invoke via their respective FFI layers. Whether using Go's *Tx type, Python's connection context managers, or Java's Transaction objects, each binding ultimately calls the same native functions to begin, commit, or rollback transactions on the remote Turso database.

Can I use the Turso language bindings with self-hosted libSQL instances?

Yes, because the Rust driver implements the libSQL wire protocol, the language bindings can connect to any compatible endpoint, including self-hosted libSQL servers or local SQLite files, by specifying the appropriate connection string in go.Open, turso.connect, or the equivalent constructor in Java and .NET.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →