A database for a frontend-only app, with no server to run

Seige gives a browser app a SQL database without a database server. Each user gets an encrypted SQLite database in their own Seige account. Your app reads and writes it with a chainable query API from the browser. Tables are created on the first insert, and there are no access policies to write, because each database belongs to one user.

import { createSeige } from "@seige_sdk/sdk";

const seige = createSeige({ appName: "Budget" });

await seige.from("expenses").insert({ label: "Groceries", amount: 42.5 });

const { data: recent, error } = await seige
  .from("expenses")
  .select("id, label, amount")
  .gte("amount", 10)
  .order("created_at", { ascending: false })
  .limit(20);

await seige.from("expenses").update({ amount: 40 }).eq("id", recent[0].id);

How the database behaves

Supported filters are eq, neq, gt, gte, lt, lte, like, ilike, is, in, contains, containedBy, overlaps, match, not, filter and or. Modifiers are order, limit, range, single and maybeSingle.

Constraints and migrations

For unique or required columns, define tables in SQL migration files and pass them to createSeige({ migrations }). Migrations run once each, in name order, and are recorded inside the user's database.

const seige = createSeige({
  migrations: [
    { name: "001_expenses", sql: "create table expenses (id integer primary key, label text not null, amount real)" },
  ],
});

Encryption and access

Each change is encrypted in the browser before it is sent. Seige's servers store ciphertext and do not hold the keys to read it. Your app can reach only the folders the user approved. The user can disconnect the app at any time, and the database stays in their account.

Limits

This guide is also available as Markdown for coding agents.