# 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.

```js
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

- The first insert into a table creates it, with an `id` (a UUID unless you
  supply one) and a `created_at` timestamp. A new key becomes a new column.
- Each column's type comes from the first value written to it. Booleans read
  back as booleans, and objects and arrays read back as JSON.
- Each query is one transaction and is saved to Seige before it resolves. If
  Seige is unreachable, the change stays in an encrypted queue in the browser
  and is sent when the connection returns.
- A query reads one table. Query related tables separately and join the
  results in your app, or run SQL through `seige.db.open()`.
- `update()` and `delete()` require at least one filter.
- Constraint errors use Postgres codes, such as `23505` for a unique violation.

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.

```js
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

- 32 MiB per database, and 10,000 rows or 8 MiB per query result.
- One active writer per database. The SDK does not merge concurrent edits from
  several users, so it does not suit data that many users edit together.
- Each user needs a Seige account. Account creation is currently open to
  invited usernames.

## Related guides

- [Store user files from a browser app](/guides/file-storage-for-browser-apps/)
- [Instructions for coding agents](/guides/backend-for-coding-agents/)
- [Query reference](/developers/#queries)
