{"id":16843,"library":"libsql","title":"libSQL JavaScript Client (@libsql/client)","description":"The libSQL JavaScript Client (`@libsql/client`) is a comprehensive TypeScript/JavaScript driver for interacting with libSQL databases, a fork of SQLite. It aims for API compatibility with `better-sqlite3`, offering both synchronous and opt-in promise-based APIs. This client supports Node.js, Bun, Deno, and web browsers, facilitating connections to in-memory, local file-based, and remote libSQL instances (including Turso databases). Key differentiators include support for embedded replicas (local SQLite files that sync with remote Turso databases for offline capabilities), remote access over HTTP/WebSockets, and advanced features like encryption at rest and AI/Vector Search integration when used with Turso. The current stable version is `0.5.29`, with active development towards a `0.6.x` release, which has introduced some breaking changes and new features. The npm package `libsql` is deprecated; users should install and import from `@libsql/client` instead.","status":"active","version":"0.5.29","language":"javascript","source_language":"en","source_url":"https://github.com/tursodatabase/libsql-js","tags":["javascript","libsql","typescript"],"install":[{"cmd":"npm install libsql","lang":"bash","label":"npm"},{"cmd":"yarn add libsql","lang":"bash","label":"yarn"},{"cmd":"pnpm add libsql","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Runtime dependency for WebSocket connections in Node.js environments; may not be needed in Bun, Deno, or browsers where WebSockets are native.","package":"ws","optional":true}],"imports":[{"note":"Primary entry point for creating a libSQL database client. The CommonJS `require` syntax works but is less idiomatic for modern TypeScript/ESM projects. Ensure your environment supports ESM for direct `import`.","wrong":"const createClient = require('@libsql/client').createClient;","symbol":"createClient","correct":"import { createClient } from '@libsql/client';"},{"note":"Import the `Client` interface using `import type` for type-only imports, which helps with tree-shaking and avoids runtime dependencies in TypeScript projects. Using `import { Client }` without `type` is generally not needed as `Client` is an interface.","wrong":"import { Client } from '@libsql/client';","symbol":"Client","correct":"import type { Client } from '@libsql/client';"},{"note":"Import the `Config` type for defining client connection options. This is a type-only import. The configuration object for `createClient` takes a `Config` type.","symbol":"Config","correct":"import type { Config } from '@libsql/client';"},{"note":"For `better-sqlite3` compatible synchronous API in Node.js, import `Database` from `'@libsql/client/node'`. For the promise-based API, import from `'@libsql/client/promise'`. The default `@libsql/client` import is typically for `createClient` which is async and handles different connection types.","wrong":"import Database from '@libsql/client';","symbol":"Database (legacy/sync API)","correct":"import Database from '@libsql/client/node'; // for Node.js sync API\nimport Database from '@libsql/client/promise'; // for Node.js async API"}],"quickstart":{"code":"import { createClient } from '@libsql/client';\nimport 'dotenv/config';\n\nconst tursoUrl = process.env.TURSO_DATABASE_URL ?? '';\nconst tursoAuthToken = process.env.TURSO_AUTH_TOKEN ?? '';\n\nif (!tursoUrl) {\n  console.error('TURSO_DATABASE_URL environment variable is not set.');\n  process.exit(1);\n}\n\n// Create a client for a remote Turso database\nconst client = createClient({\n  url: tursoUrl,\n  authToken: tursoAuthToken,\n});\n\nasync function runExample() {\n  try {\n    // Create a table if it doesn't exist\n    await client.execute(`\n      CREATE TABLE IF NOT EXISTS users (\n        id INTEGER PRIMARY KEY AUTOINCREMENT,\n        name TEXT NOT NULL,\n        email TEXT UNIQUE NOT NULL\n      );\n    `);\n    console.log('Table \"users\" ensured to exist.');\n\n    // Insert data (batch operation for efficiency)\n    const insertResult = await client.batch(\n      [\n        { sql: 'INSERT INTO users (name, email) VALUES (?, ?)', args: ['Alice', 'alice@example.com'] },\n        { sql: 'INSERT INTO users (name, email) VALUES (?, ?)', args: ['Bob', 'bob@example.com'] }\n      ],\n      'write'\n    );\n    console.log('Inserted two users.', insertResult);\n\n    // Query data\n    const selectResult = await client.execute('SELECT * FROM users WHERE name = ?', ['Alice']);\n    console.log('Query result for Alice:', selectResult.rows);\n\n    // Update data within a transaction\n    await client.transaction(async tx => {\n      await tx.execute('UPDATE users SET name = ? WHERE email = ?', ['Alicia', 'alice@example.com']);\n      // console.log('Updated Alice to Alicia within transaction.');\n      throw new Error(\"Simulating a rollback for demonstration purposes\"); // Transaction will roll back\n    }).catch(e => {\n        if (e.message !== \"Simulating a rollback for demonstration purposes\") {\n            throw e; // Re-throw if it's not our simulated error\n        }\n        console.log(\"Transaction rolled back as intended.\");\n    });\n    \n    // Verify if update was rolled back\n    const verifyResult = await client.execute('SELECT name FROM users WHERE email = ?', ['alice@example.com']);\n    console.log('Name after attempted update (should be Alice):', verifyResult.rows[0].name);\n\n  } catch (e) {\n    console.error('An error occurred:', e);\n  }\n}\n\nrunExample();","lang":"typescript","description":"This quickstart demonstrates how to connect to a remote libSQL (Turso) database, create a table, insert data using a batch operation, query data, and perform an update within a transaction, including a simulated rollback. It uses environment variables for secure credential management."},"warnings":[{"fix":"Change your `package.json` dependency from `\"libsql\": \"^x.y.z\"` to `\"@libsql/client\": \"^x.y.z\"` and update import paths accordingly, e.g., `import { createClient } from '@libsql/client';`.","message":"The `libsql` npm package is deprecated. Users should migrate to `@libsql/client` for the official JavaScript/TypeScript client.","severity":"breaking","affected_versions":">=0.1.0"},{"fix":"Upgrade `@libsql/client` to version `0.6.2` or higher to resolve database push and JSON parsing issues.","message":"Versions of `@libsql/client` greater than `0.6.0` had issues pushing to Turso schema databases, particularly when integrated with ORMs like Drizzle. A bug fix was released in `0.6.2` addressing an `Unexpected end of JSON input` error.","severity":"breaking","affected_versions":"0.6.1"},{"fix":"For maximum compatibility and to leverage libSQL's full feature set (especially for remote connections or embedded replicas), prefer using `createClient` and its async methods. Thoroughly test migration from `better-sqlite3` to ensure expected behavior.","message":"While `@libsql/client` provides a `better-sqlite3` compatible API, using `Database` directly from `libsql/node` or `libsql/promise` might retain synchronous blocking behavior in some contexts or have subtle differences in error handling or advanced features compared to the native `better-sqlite3` library.","severity":"gotcha","affected_versions":">=0.5.0"},{"fix":"Ensure `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN` environment variables are correctly set and accessible in your deployment environment. For local `sqld` instances, add `?tls=0` to the URL if not using TLS. Use `libsql://` prefix for Turso URLs. Double-check URL format and token validity.","message":"Connecting to remote libSQL instances (e.g., Turso) requires a valid URL and an authentication token. Incorrect or missing credentials, or an invalid URL format, will lead to connection failures.","severity":"gotcha","affected_versions":">=0.5.0"},{"fix":"When deploying to serverless functions, Cloudflare Workers, or browsers, ensure you use `http(s):`, `ws(s):`, or `libsql:` URLs for remote connections. Avoid `file:` URLs in these environments.","message":"The client automatically selects an implementation based on the URL scheme (e.g., `file:` for local SQLite, `http(s):` or `ws(s):` for remote). `file:` URLs are only supported in Node.js and will not work in browser or serverless environments without local filesystem access.","severity":"gotcha","affected_versions":">=0.5.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Verify that `process.env.TURSO_DATABASE_URL` or the directly provided URL string is in the correct format (e.g., `libsql://your-db-slug-your-org.turso.io` or `file:./local.db`). Ensure environment variables are loaded (e.g., with `dotenv`).","cause":"The connection URL provided to `createClient` is malformed or invalid, or environment variables are not correctly loaded/passed.","error":"Error [LibsqlError]: URL_INVALID: The URL is not in a valid format"},{"fix":"Upgrade `@libsql/client` to version `0.6.2` or newer. This issue was a specific bug fixed in that release.","cause":"This error was observed in `@libsql/client` version `0.6.1` due to an internal parsing issue, particularly with database push operations.","error":"Error: Unexpected end of JSON input"},{"fix":"Always check if `selectResult.rows` exists and has elements before accessing `selectResult.rows[0]`. Operations like `client.execute('INSERT ...')` return `ResultSet` but `rows` array might be empty. Use `ResultSet.rowsAffected` for mutation operations. Consider `client.transaction` for complex read/write operations.","cause":"Attempting to access properties like `.rows` on a `ResultSet` that might be empty or undefined, or incorrectly assuming an `execute` call will always return rows when it's an `INSERT` or `UPDATE`.","error":"Cannot read properties of undefined (reading 'rows') or similar for query results"},{"fix":"Implement logic to prevent duplicate insertions, such as checking for existing records before inserting, or handling the error gracefully by providing user feedback. Ensure your application logic respects database constraints.","cause":"Attempting to insert or update a record with a value in a `UNIQUE` column (e.g., `email`) that already exists in the database.","error":"Error: SQLite error: UNIQUE constraint failed: users.email"}],"ecosystem":"npm","meta_description":null}