Use Turso Database from Node.js and browsers via the @tursodatabase/database package.
Turso Database is currently in BETA. It may contain bugs and unexpected behavior. Use caution with production data and ensure you have backups.
The @tursodatabase/database package provides a synchronous better-sqlite3-style API for Turso Database. It ships a native Node.js binding as well as a WebAssembly build for browser environments.
Use db.exec() to run one or more SQL statements without returning rows. Use db.prepare() to create a Statement and call .all(), .get(), or .run() on it.
import { connect } from '@tursodatabase/database';const db = await connect(':memory:');// Execute DDL directlydb.exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)');// Insert a rowconst insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');insert.run('Alice', '[email protected]');insert.run('Bob', '[email protected]');// Select all rowsconst users = db.prepare('SELECT * FROM users').all();console.log(users);// [// { id: 1, name: 'Alice', email: '[email protected]' },// { id: 2, name: 'Bob', email: '[email protected]' }// ]
.all() returns an array of plain objects keyed by column name. .get() returns the first matching row or undefined. Use .iterate() to consume results lazily as a generator:
import { connect } from '@tursodatabase/database';const db = await connect(':memory:');db.exec(` CREATE TABLE logs (id INTEGER PRIMARY KEY, msg TEXT); INSERT INTO logs VALUES (1, 'start'); INSERT INTO logs VALUES (2, 'stop');`);const stmt = db.prepare('SELECT * FROM logs');// Iterate lazilyfor (const row of stmt.iterate()) { console.log(row.id, row.msg);}// Inspect column metadataconst columns = stmt.columns();console.log(columns); // [{ name: 'id', type: 'INTEGER' }, { name: 'msg', type: 'TEXT' }]
Wrap a function with db.transaction() to execute it atomically. The returned function begins a BEGIN / COMMIT block around the wrapped function, rolling back on any thrown error.
import { connect } from '@tursodatabase/database';const db = await connect(':memory:');db.exec('CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)');db.prepare('INSERT INTO accounts VALUES (?, ?)').run(1, 1000);db.prepare('INSERT INTO accounts VALUES (?, ?)').run(2, 500);const transfer = db.transaction((fromId, toId, amount) => { const debit = db.prepare( 'UPDATE accounts SET balance = balance - ? WHERE id = ?' ); const credit = db.prepare( 'UPDATE accounts SET balance = balance + ? WHERE id = ?' ); debit.run(amount, fromId); credit.run(amount, toId);});// Execute atomically — rolls back if either statement throwstransfer(1, 2, 100);console.log(db.prepare('SELECT * FROM accounts').all());// [{ id: 1, balance: 900 }, { id: 2, balance: 600 }]
The transaction function also exposes .deferred, .immediate, and .exclusive variants for fine-grained isolation:
For browser environments, use the @tursodatabase/wasm package. The API is identical to the native package.
import { connect } from '@tursodatabase/wasm';const db = await connect(':memory:');db.exec('CREATE TABLE notes (id INTEGER PRIMARY KEY, text TEXT)');db.prepare('INSERT INTO notes (text) VALUES (?)').run('Hello from the browser!');const notes = db.prepare('SELECT * FROM notes').all();console.log(notes);
The WASM build runs entirely in the browser with no server required. Database state is stored in memory and lost on page reload unless you persist it via the File System Access API or IndexedDB.
import { connect } from '@tursodatabase/database';const db = await connect(':memory:');db.exec(` CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP )`);const insertPost = db.prepare( 'INSERT INTO posts (title, content) VALUES (?, ?)');const createPost = db.transaction((title, content) => { const result = insertPost.run(title, content); return result.lastInsertRowid;});const id1 = createPost('Hello, Turso!', 'This is the first post.');const id2 = createPost('Second post', 'More content here.');console.log('Created posts:', id1, id2);const posts = db.prepare('SELECT id, title FROM posts ORDER BY id').all();for (const post of posts) { console.log(`${post.id}: ${post.title}`);}