Skip to content

Repository files navigation

SQLiteBruv

A small, zero-dependency SQLite query builder for Bun with Prisma-style migrations. Supports local SQLite, Cloudflare D1, and Turso.

npm versionLicense: MITnpm

Most Effective Query Builder and migration manager SQLite supporting D1/Turso and Bun's by default.

v2 now a full sqlite only orm, enjoy and support & contribute!

Install

bun add sqlitebruv

Quick start

Define your schema in ./bruv/schema.prisma:

modelUser {idString@id@default(uuid())emailString@uniquenameString?ageInt?}modelPost {idString@id@default(uuid())titleStringuserIdString}

Initialize the database. Schema is auto-loaded from ./bruv/schema.prisma:

import{SqliteBruv}from"sqlitebruv";constdb=newSqliteBruv({localFile: "./app.db",});

Query:

awaitdb.from("users").insert({name: "friday",email: "f@dev.io"});constusers=awaitdb.from("users").where("age > ?",18).get();constone=awaitdb.from("users").where("id = ?",id).getOne();

Platforms

// Cloudflare D1constdb=newSqliteBruv({D1Config: {accountId: process.env.CFAccountId,databaseId: process.env.D1databaseId,apiKey: process.env.CFauthorizationToken,},});// Tursoconstdb=newSqliteBruv({TursoConfig: {url: process.env.TURSO_URL,authToken: process.env.TURSO_AUTH_TOKEN,},});// Local SQLite (default)constdb=newSqliteBruv({localFile: "./app.db",});

Query API

// Selectdb.from("users").select("id","name").get();// Where chainsdb.from("users").where("age > ?",18).andWhere("country = ?","NG").orWhere("role = ?","admin").get();// Paginationdb.from("users").orderBy("name","ASC").limit(10).offset(20).get();// Single recorddb.from("users").where("id = ?",id).getOne();// Countdb.from("users").where("active = ?",true).count();// Insert (id is auto-generated)db.from("users").insert({name: "friday",email: "f@dev.io"});// Updatedb.from("users").where("id = ?",id).update({name: "saturday"});// Deletedb.from("users").where("id = ?",id).delete();// Raw SQLdb.raw("SELECT * FROM users WHERE id = ?",[id]);

Caching

constusers=awaitdb.from("users").get({cacheAs: "all-users"});// Laterdb.invalidateCache("all-users");

Migrations

Prisma-style CLI. Schema source of truth is ./bruv/schema.prisma. Migrations live in ./bruv/migrations/.

# Generate + apply migration (uses local dev.db)
npx bruv-cli migrate dev --name add_age_column
# Apply pending migrations to production DB (reads env vars)
npx bruv-cli migrate deploy
# Rollback last migration
npx bruv-cli migrate reset
# Check status
npx bruv-cli migrate status
# Push schema directly, no migration file
npx bruv-cli db push

Connection is resolved from environment variables:

Env varsTarget
TURSO_URL + TURSO_AUTH_TOKENTurso
CFAccountId + D1databaseId + CFauthorizationTokenD1
DB_FILELocal file path
(none)./main.db

migrate dev always targets ./bruv/dev.db for local iteration.

Migration files use -- --> up / -- --> down markers and run inside transactions:

-- --> upCREATETABLEIF NOT EXISTS users (
id textPRIMARY KEYNOT NULL,
email TEXT UNIQUE NOT NULL,
name TEXT
);
-- --> downDROPTABLE users;

JSON query interface

For exposing queries over HTTP without writing per-route SQL:

constresult=awaitdb.executeJsonQuery({from: "users",action: "get",where: [{condition: "age > ?",params: [18]}],orderBy: {column: "name",direction: "ASC"},limit: 10,});

Actions: get, getOne, insert, update, delete, count.

Security

The query builder rejects dangerous input at the condition level:

  • Parameterized queries only — no string interpolation
  • Blocked patterns: ; DROP, UNION, DELETE, INSERT, UPDATE, ALTER, EXEC
  • Whitelisted operators: =, >, <, >=, <=, LIKE, IN, BETWEEN, IS NULL, IS NOT NULL
  • Max 100 params per query, max 1000 chars per string param

raw() bypasses all validation — use it for migrations and admin queries only.

Examples

// ✅ Safe queriesdb.from("users").where("email LIKE ?","%@example.com")// ✅ Safe.andWhere("role = ?","admin")// ✅ Safe.get();db.from("users").where("age > ?",18).andWhere("status = ?","active").orWhere("role IN (?)",["admin","mod"]);// ❌ These will throw security errors:db.where("1=1; DROP TABLE users;");// Dangerous patterndb.where("col = (SELECT ...)");// Complex subqueries blockeddb.where("name = ?","a".repeat(1001));// String too long

Contributing

  1. Fork
  2. Branch (git checkout -b feature/your thing)
  3. Commit
  4. PR

License

MIT

About

💃Most Effective Query Builder and migration manager SQLite supporting D1/Turso and Bun's by default.

Topics

Resources

Stars

19 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages