@supabase/lite 0.9.0 → 0.9.1-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FEATURES.md +176 -0
- package/LIMITATIONS.md +1 -0
- package/README.md +1 -0
- package/STATUS.md +7 -1
- package/dist/cli/index.js +86 -86
- package/dist/db/postgres/pglite/PgliteConnection.js +17 -17
- package/dist/index.d.ts +26 -2
- package/dist/index.js +55 -55
- package/dist/vite/index.d.ts +26 -2
- package/docs/auth/email.mdx +214 -0
- package/docs/auth/not-supported.mdx +57 -0
- package/docs/auth/overview.mdx +52 -0
- package/docs/auth/supported-flows.mdx +120 -0
- package/docs/cli/overview.mdx +112 -0
- package/docs/cli/telemetry.mdx +34 -0
- package/docs/compatibility.mdx +115 -0
- package/docs/database/backends.mdx +118 -0
- package/docs/database/data-api.mdx +90 -0
- package/docs/database/functions-triggers.mdx +93 -0
- package/docs/database/migrations.mdx +93 -0
- package/docs/database/overview.mdx +66 -0
- package/docs/database/postgres-sqlite-translation.mdx +130 -0
- package/docs/database/rls.mdx +159 -0
- package/docs/database/schemas.mdx +58 -0
- package/docs/index.mdx +49 -0
- package/docs/integrations/embedded.mdx +83 -0
- package/docs/integrations/frameworks.mdx +83 -0
- package/docs/integrations/vite.mdx +85 -0
- package/docs/llms.txt +52 -0
- package/docs/other/edge-functions.mdx +34 -0
- package/docs/other/realtime.mdx +22 -0
- package/docs/quickstart.mdx +150 -0
- package/docs/running.mdx +117 -0
- package/docs/storage/adapters.mdx +75 -0
- package/docs/storage/limitations.mdx +30 -0
- package/docs/storage/overview.mdx +82 -0
- package/docs/upgrade.mdx +108 -0
- package/package.json +4 -1
- package/skills/supalite/SKILL.md +5 -3
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Compatibility"
|
|
3
|
+
description: "Capability-level support matrix for the Data API, Auth, Storage, RLS, Realtime, and Edge Functions across SQLite, PGlite, and Postgres."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
Compatibility is measured against the `@supabase/supabase-js` surface: does code written for Supabase keep working when pointed at Supabase Lite. Direct Postgres wire-protocol access (`psql`, raw SQL clients) is not a target.
|
|
9
|
+
|
|
10
|
+
<Aside type="note">
|
|
11
|
+
This page is a capability-level rollup. The authoritative, per-method matrix ships in-package as `STATUS.md` (with effort/blocker detail in `FEATURES.md`) and updates every `npm install`. If you need an exact count for a specific method, check that file rather than this page.
|
|
12
|
+
</Aside>
|
|
13
|
+
|
|
14
|
+
## The backend axis
|
|
15
|
+
|
|
16
|
+
Supabase Lite runs on two families of database backend, and support differs between them:
|
|
17
|
+
|
|
18
|
+
- **SQLite** (`bun:sqlite`, `node:sqlite`, SQLite WASM, Cloudflare D1/DO): the primary, zero-dependency path. Most gaps below are SQLite-specific platform limits (no range types, no stored procedures, no native full-text ranking).
|
|
19
|
+
- **PGlite / Postgres**: run the same Data API and Auth implementation against a real Postgres engine. Many features that are partial or unsupported on SQLite work natively here, since RLS, `rpc()`, ranges, and regex all fall back to real Postgres behavior.
|
|
20
|
+
|
|
21
|
+
Switching backends is a config change (`driver = "pglite"` or `"postgres"` in `config.toml`), not a code change. See [Database backends](/database/backends) for setup.
|
|
22
|
+
|
|
23
|
+
## Data API (PostgREST)
|
|
24
|
+
|
|
25
|
+
CRUD, filtering, embedding, and RLS over your tables. This is the most complete surface: **53/74** `supabase-js` query-builder methods on SQLite, **72/74** on Postgres/PGlite.
|
|
26
|
+
|
|
27
|
+
| Capability | SQLite | PGlite | Postgres | Coverage |
|
|
28
|
+
|---|:---:|:---:|:---:|---|
|
|
29
|
+
| Core CRUD (select/insert/update/delete/upsert) | ✅ | ✅ | ✅ | 6/6 on all backends |
|
|
30
|
+
| Comparison filters (eq, gt, in, is, …) | ✅ | ✅ | ✅ | 10/10 on all backends |
|
|
31
|
+
| Pattern matching (like/ilike + quantified) | ✅ | ✅ | ✅ | 6/6 on all backends |
|
|
32
|
+
| Resource embedding (FK joins, `!inner`, spreads, nested, aggregates) | ✅ | ✅ | ✅ | 5/5 on all backends |
|
|
33
|
+
| RLS enforcement | ✅ | ✅ | ✅ | App-layer rewrite on SQLite, native on Postgres/PGlite |
|
|
34
|
+
| Array/JSON containment (`contains`, `containedBy`, `overlaps`) | ⚠️ | ✅ | ✅ | Scalar arrays + shallow objects only on SQLite |
|
|
35
|
+
| Full-text search (fts/plfts/phfts/wfts) | ⚠️ | ✅ | ✅ | LIKE-based lexeme approximation on SQLite, not FTS5/tsvector |
|
|
36
|
+
| Regex (`regexMatch`/`regexIMatch`) | ⚠️ | ✅ | ✅ | Simple anchored/literal patterns only on SQLite |
|
|
37
|
+
| `schema()` (multi-schema) | ⚠️ | ✅ | ✅ | On `sqlite-postgres`, schema-qualified DDL is flattened into one namespace and `schema()`/`Accept-Profile` routing resolves, but there's no real namespace isolation; the bare `sqlite` driver has no schema handling |
|
|
38
|
+
| Advanced postgres features (`rangeGt`, `rpc()`, `eq(any)`, …) | ❌ | ✅ | ✅ | No range types in SQLite. `geojson()` and `rollback()` are the only gaps on Postgres/PGlite. |
|
|
39
|
+
| **Total** | **53/74** | **72/74** | **72/74** | |
|
|
40
|
+
|
|
41
|
+
## Auth (GoTrue)
|
|
42
|
+
|
|
43
|
+
Email/password, OTP, sessions, RLS auth context, and OAuth sign-in with `github`/`google` are solid. Admin API, manual identity linking, other OAuth providers, and MFA are the main gaps, and behave the same regardless of database backend (Auth doesn't have a SQLite/Postgres split the way the Data API does). One exception: on the Cloudflare D1 backend, multi-statement Auth transaction spans (OAuth callback/token writes, email-change and other OTP verification) run best-effort without a wrapping transaction (D1 has no callback transaction API); single-statement guards still prevent auth-code/state reuse. All other backends, including Durable Objects, are fully transactional.
|
|
44
|
+
|
|
45
|
+
| Capability | SQLite | PGlite | Postgres | Coverage |
|
|
46
|
+
|---|:---:|:---:|:---:|---|
|
|
47
|
+
| Email + password sign-up/sign-in | ✅ | ✅ | ✅ | |
|
|
48
|
+
| Magic link / email OTP | ✅ | ✅ | ✅ | signup, magiclink, recovery, email_change, reauthentication |
|
|
49
|
+
| JWT issuance, refresh rotation, sessions | ✅ | ✅ | ✅ | |
|
|
50
|
+
| Password recovery / resend / reauthenticate | ✅ | ✅ | ✅ | |
|
|
51
|
+
| RLS auth context (`auth.uid()`, `auth.role()`, `auth.jwt()`) | ✅ | ✅ | ✅ | Shared with the Data API |
|
|
52
|
+
| API keys (`sb_publishable_*`/`sb_secret_*`) | ✅ | ✅ | ✅ | Enforced on `/rest/v1`/`/auth/v1` when configured; legacy JWT-as-apikey not supported |
|
|
53
|
+
| OAuth / social sign-in | ⚠️ | ⚠️ | ⚠️ | `github`/`google` only; PKCE + implicit flows, automatic account linking. Other providers (incl. Apple) planned |
|
|
54
|
+
| Anonymous sign-in | 🔄 | 🔄 | 🔄 | Planned |
|
|
55
|
+
| Identity linking | ⚠️ | ⚠️ | ⚠️ | Automatic linking on OAuth sign-in works; manual `linkIdentity`/`unlinkIdentity` planned |
|
|
56
|
+
| Admin user API | 🔄 | 🔄 | 🔄 | Planned |
|
|
57
|
+
| MFA / TOTP / WebAuthn | ⚫ | ⚫ | ⚫ | Not planned |
|
|
58
|
+
| **Total** | **13/63** | **13/63** | **13/63** | 13 backend endpoints implemented; 10 additional `supabase-js` methods are client-side only (N/A) |
|
|
59
|
+
|
|
60
|
+
See [Auth overview](/auth/overview) and [Not supported](/auth/not-supported) for the full breakdown.
|
|
61
|
+
|
|
62
|
+
## Storage
|
|
63
|
+
|
|
64
|
+
Gated behind `EXPERIMENTAL_STORAGE`. CRUD, public buckets, signed URLs, and image transforms are done; role-based access control is the main gap.
|
|
65
|
+
|
|
66
|
+
| Capability | SQLite | PGlite | Postgres | Coverage |
|
|
67
|
+
|---|:---:|:---:|:---:|---|
|
|
68
|
+
| Bucket CRUD | ✅ | ✅ | ✅ | |
|
|
69
|
+
| Object CRUD (upload/download/list/move/copy/remove/info) | ✅ | ✅ | ✅ | |
|
|
70
|
+
| Signed URLs (download, batch, upload) | ✅ | ✅ | ✅ | |
|
|
71
|
+
| Image transforms (Sharp, Cloudflare) | ✅ | ✅ | ✅ | |
|
|
72
|
+
| Storage backends (filesystem, S3-compatible) | ✅ | ✅ | ✅ | |
|
|
73
|
+
| Role-based access (service_role/anon/authenticated gating) | ⚠️ | ⚠️ | ⚠️ | API keys now resolve roles for route-level checks; no per-object RLS yet |
|
|
74
|
+
| RLS policies on storage objects | 🔄 | 🔄 | 🔄 | Planned |
|
|
75
|
+
| **Total** | **20/20 methods** | **20/20 methods** | **20/20 methods** | Access control and `/status` health endpoint pending |
|
|
76
|
+
|
|
77
|
+
See [Storage overview](/storage/overview) and [Storage limitations](/storage/limitations).
|
|
78
|
+
|
|
79
|
+
## Row Level Security (RLS)
|
|
80
|
+
|
|
81
|
+
RLS works across all backends but is enforced differently: SQLite rewrites the PostgREST query AST at the application layer, while PGlite/Postgres use native Postgres RLS.
|
|
82
|
+
|
|
83
|
+
| Feature | SQLite | PGlite | Postgres |
|
|
84
|
+
|---|:---:|:---:|:---:|
|
|
85
|
+
| `ENABLE ROW LEVEL SECURITY`, `USING`, `WITH CHECK` | ✅ | ✅ | ✅ |
|
|
86
|
+
| Permissive / restrictive policies, `FOR` command targeting, `TO role` | ✅ | ✅ | ✅ |
|
|
87
|
+
| `auth.uid()` / `auth.jwt()` in policies | ✅ | ✅ | ✅ |
|
|
88
|
+
| Subquery `WITH CHECK` on INSERT | ❌ | ✅ | ✅ |
|
|
89
|
+
| `DEFAULT auth.uid()` on columns | ❌ | ✅ | ✅ |
|
|
90
|
+
| Standalone `DROP POLICY` / `ALTER POLICY` | ✅ | ✅ | ✅ |
|
|
91
|
+
|
|
92
|
+
See [Database: RLS](/database/rls) for the enforcement model and workarounds.
|
|
93
|
+
|
|
94
|
+
## Realtime and Edge Functions
|
|
95
|
+
|
|
96
|
+
Both are planned but not started: config schemas exist, no runtime yet.
|
|
97
|
+
|
|
98
|
+
| Product | SQLite | PGlite | Postgres |
|
|
99
|
+
|---|:---:|:---:|:---:|
|
|
100
|
+
| Realtime | 🔄 | 🔄 | 🔄 |
|
|
101
|
+
| Edge Functions | 🔄 | 🔄 | 🔄 |
|
|
102
|
+
|
|
103
|
+
See [Realtime](/other/realtime) and [Edge Functions](/other/edge-functions) for the planned design.
|
|
104
|
+
|
|
105
|
+
## Legend
|
|
106
|
+
|
|
107
|
+
| Icon | Meaning |
|
|
108
|
+
|---|---|
|
|
109
|
+
| ✅ | Supported end-to-end |
|
|
110
|
+
| ⚠️ | Partial, works with caveats |
|
|
111
|
+
| 🔄 | Planned, not built yet |
|
|
112
|
+
| ❌ | Not feasible on this path |
|
|
113
|
+
| ⚫ | Not applicable |
|
|
114
|
+
|
|
115
|
+
For the full Supabase feature list this compatibility matrix is measured against, see the [Supabase docs](https://supabase.com/docs).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Backends"
|
|
3
|
+
description: "SQLite drivers vs PGlite/Postgres: how Supabase Lite picks a database, and how to switch."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Supabase Lite runs on one of two database families. Which one you're on determines which parts of the Data API, RLS, and schema translation are fully available versus partial or missing. Every other page in this section links back here for "switch backend to get X."
|
|
10
|
+
|
|
11
|
+
## The two families
|
|
12
|
+
|
|
13
|
+
Two independent choices are in play. The **SQLite runtime binding** is auto-selected based on where your code runs; the **`driver`** value in `config.toml` picks how your schema DDL is interpreted.
|
|
14
|
+
|
|
15
|
+
**SQLite backends** run in-process with zero external dependencies. The binding is automatic:
|
|
16
|
+
|
|
17
|
+
| Runtime | SQLite binding | Selection |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Bun | `bun:sqlite` | Automatic |
|
|
20
|
+
| Node.js ≥ 22 | `node:sqlite` | Automatic |
|
|
21
|
+
| Browser | `@sqlite.org/sqlite-wasm` | Automatic |
|
|
22
|
+
| Cloudflare Workers + Durable Objects | workerd / D1 SQLite | `@supabase/lite/workerd` |
|
|
23
|
+
|
|
24
|
+
On top of the binding, the `driver` value selects the DDL dialect:
|
|
25
|
+
|
|
26
|
+
- **`sqlite-postgres` (the default)**: you write Postgres DDL in `schemas/*.sql` and Supabase Lite deparses it to SQLite. This is what `lite init` scaffolds, and what every "SQLite path" note in these docs assumes. It doubles as a compatibility check for moving to a real Postgres backend later, since your schema is authored as Postgres.
|
|
27
|
+
- **`sqlite`**: you write raw SQLite DDL yourself, with no translation. This is a niche choice: reach for it only if you specifically want to hand-write SQLite and skip the Postgres layer. Postgres-only features that depend on the translator, including RLS policy parsing, are not available on this bare path.
|
|
28
|
+
|
|
29
|
+
**Postgres backends** run real Postgres semantics, either embedded or networked:
|
|
30
|
+
|
|
31
|
+
| Backend | `driver` | Notes |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| PGlite | `pglite` | In-process WASM Postgres. No separate server. |
|
|
34
|
+
| Postgres | `postgres` | Remote/local Postgres over the `postgres` node driver. |
|
|
35
|
+
|
|
36
|
+
## The trade-off
|
|
37
|
+
|
|
38
|
+
**SQLite** is fast, has no external process to run, and works identically in Node, Bun, the browser, and Cloudflare Workers. The cost: no arrays, no range types, no regex engine, and no stored-procedure model. Concretely, on SQLite: `rpc()` doesn't work, range operators (`rangeGt`, etc.) and quantified comparisons (`eq(any)`, etc.) aren't implemented, `textSearch()` is a LIKE-based lexeme approximation rather than real FTS5/tsvector ranking, `regexMatch`/`regexIMatch` only handle simple anchored patterns, and columns can't default to `auth.uid()`. See [Data API divergences](/database/data-api) for the complete list.
|
|
39
|
+
|
|
40
|
+
**PGlite and Postgres** run your schema as real Postgres. `rpc()`, range types, regex (`~`/`~*`), quantified comparisons, full-text search, and `DEFAULT auth.uid()` on columns all work exactly as they would on hosted Supabase. RLS is enforced natively by Postgres rather than emulated at the application layer. The cost is a slightly heavier runtime (PGlite ships a WASM Postgres build; Postgres requires a running server).
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Selecting a backend
|
|
44
|
+
|
|
45
|
+
Set `driver` and `url` under `[db]` in `supabase/config.toml`:
|
|
46
|
+
|
|
47
|
+
<Tabs>
|
|
48
|
+
<TabItem label="sqlite-postgres (default)">
|
|
49
|
+
```toml
|
|
50
|
+
[db]
|
|
51
|
+
driver = "sqlite-postgres"
|
|
52
|
+
url = "file:./supabase/.temp/data.db"
|
|
53
|
+
```
|
|
54
|
+
</TabItem>
|
|
55
|
+
<TabItem label="sqlite (raw DDL)">
|
|
56
|
+
```toml
|
|
57
|
+
[db]
|
|
58
|
+
driver = "sqlite"
|
|
59
|
+
url = "file:./supabase/.temp/data.db"
|
|
60
|
+
```
|
|
61
|
+
</TabItem>
|
|
62
|
+
<TabItem label="PGlite">
|
|
63
|
+
```toml
|
|
64
|
+
[db]
|
|
65
|
+
driver = "pglite"
|
|
66
|
+
url = "file:./supabase/.temp/data"
|
|
67
|
+
```
|
|
68
|
+
</TabItem>
|
|
69
|
+
<TabItem label="Postgres">
|
|
70
|
+
```toml
|
|
71
|
+
[db]
|
|
72
|
+
driver = "postgres"
|
|
73
|
+
url = "postgres://user:password@localhost:5432/postgres"
|
|
74
|
+
```
|
|
75
|
+
</TabItem>
|
|
76
|
+
</Tabs>
|
|
77
|
+
|
|
78
|
+
`lite init --pglite` scaffolds a project preconfigured for PGlite instead of the default `sqlite-postgres`. Programmatically, pass the driver at connection time:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { createConnection } from "@supabase/lite/sqlite"; // picks the SQLite driver per runtime
|
|
82
|
+
// or
|
|
83
|
+
import { createConnection } from "@supabase/lite/pglite";
|
|
84
|
+
import { createConnection } from "@supabase/lite/postgres";
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Postgres connections run with `TimeZone=UTC` by default so `timestamptz` rendering is deterministic regardless of the host's timezone. Override via the `postgresOptions.connection.TimeZone` connection option if you need a different session timezone.
|
|
88
|
+
|
|
89
|
+
## libsql / Turso
|
|
90
|
+
|
|
91
|
+
libsql is another SQLite binding, so the same SQLite feature set and [Data API divergences](/database/data-api) apply. Unlike the built-in bindings it is not auto-selected and has no `config.toml` `driver`: you construct the connection in code and pass it to `App`, the same connection-object pattern as [Cloudflare D1](/integrations/frameworks#cloudflare-workers). What it adds on top of local SQLite is remote and replicated databases:
|
|
92
|
+
|
|
93
|
+
- **Local file / in-memory** — `url: "file:./data.db"` or `":memory:"`.
|
|
94
|
+
- **Remote (Turso)** — a `libsql://` URL plus an `authToken`.
|
|
95
|
+
- **Embedded replica** — a local `url` kept in sync from a `syncUrl` primary.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { App } from "@supabase/lite";
|
|
99
|
+
import { createLibsqlConnection } from "@supabase/lite/libsql";
|
|
100
|
+
|
|
101
|
+
const connection = await createLibsqlConnection({
|
|
102
|
+
url: process.env.TURSO_DATABASE_URL, // file:… | :memory: | libsql://…
|
|
103
|
+
authToken: process.env.TURSO_AUTH_TOKEN, // remote only
|
|
104
|
+
ddlDialect: "postgres", // or "sqlite" (see families above)
|
|
105
|
+
});
|
|
106
|
+
const app = new App({ connection });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`@libsql/client` is an optional peer dependency; install it alongside Supabase Lite. Every libsql client option (`authToken`, `syncUrl`, `encryptionKey`, `intMode`, …) is accepted on the config. Read more on [embedded usage](/integrations/embedded) and [official docs](https://docs.turso.tech).
|
|
110
|
+
|
|
111
|
+
## Where this shows up elsewhere
|
|
112
|
+
|
|
113
|
+
- [Data API divergences](/database/data-api): the exact filter/method gaps on SQLite, all resolved by switching backend.
|
|
114
|
+
- [Row Level Security](/database/rls): SQLite enforces RLS in the application layer; PGlite/Postgres use native Postgres RLS.
|
|
115
|
+
- [Postgres → SQLite translation](/database/postgres-sqlite-translation): only relevant on the SQLite path; PGlite/Postgres run your DDL unmodified.
|
|
116
|
+
- [Functions & triggers](/database/functions-triggers): SQLite supports a PL/pgSQL trigger subset; PGlite/Postgres run full PL/pgSQL.
|
|
117
|
+
|
|
118
|
+
For the underlying Supabase database concepts (connection pooling, extensions, the Postgres engine Supabase runs in production), see the [Supabase Database overview](https://supabase.com/docs/guides/database/overview).
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Data API divergences"
|
|
3
|
+
description: "Where the PostgREST-compatible Data API and supabase-js diverge on SQLite, and the workarounds."
|
|
4
|
+
---
|
|
5
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
6
|
+
|
|
7
|
+
Supabase Lite's Data API mirrors PostgREST closely enough that `@supabase/supabase-js` works unchanged for supported methods. This page lists what's unsupported, partial, and fully working, specifically on the SQLite path. Everything here works fully on PGlite and Postgres; see [Backends](/database/backends) to switch.
|
|
8
|
+
|
|
9
|
+
For the base concepts (query builder chaining, the REST API shape, response formats), see the [Data API guide](https://supabase.com/docs/guides/api) and the [supabase-js reference](https://supabase.com/docs/reference/javascript/select).
|
|
10
|
+
|
|
11
|
+
## Not supported on SQLite
|
|
12
|
+
|
|
13
|
+
<Aside type="caution">
|
|
14
|
+
These throw, no-op, or silently return wrong results on SQLite. Switch to `pglite` or `postgres` in `supabase/config.toml` to use them as-is, or apply the workaround below.
|
|
15
|
+
</Aside>
|
|
16
|
+
|
|
17
|
+
### `rpc()`
|
|
18
|
+
|
|
19
|
+
Postgres RPC depends on stored procedures (`CREATE FUNCTION ... LANGUAGE sql/plpgsql`). SQLite has no stored-procedure model. Supabase Lite doesn't introduce a parallel JS-function registry to fake it.
|
|
20
|
+
|
|
21
|
+
**Workaround**, in order of preference:
|
|
22
|
+
1. Express the logic as a SQL view or trigger in `schemas/schema.sql`.
|
|
23
|
+
2. Switch the driver to `pglite` or `postgres`: `rpc()` works there natively.
|
|
24
|
+
3. Run a regular server endpoint (Hono, Express, a Next.js route handler, or Vite middleware) and call it directly from the client.
|
|
25
|
+
|
|
26
|
+
### Embedded dotted-path filters
|
|
27
|
+
|
|
28
|
+
`.eq('rel.col', value)` (filtering an embedded resource by one of its own columns) is not rewritten into the embedded subquery on SQLite. Results come back unfiltered or error.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// Not supported on SQLite:
|
|
32
|
+
await client.from("trips").select("*, days(*)").eq("days.city", "Paris");
|
|
33
|
+
|
|
34
|
+
// Workaround: pre-resolve matching ids, then filter the parent by FK column.
|
|
35
|
+
const { data: days } = await client.from("days").select("trip_id").eq("city", "Paris");
|
|
36
|
+
await client.from("trips").select("*, days(*)").in("id", days.map(d => d.trip_id));
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Range operators
|
|
40
|
+
|
|
41
|
+
`rangeGt`, `rangeGte`, `rangeLt`, `rangeLte`, `rangeAdjacent`: SQLite has no range types, so there's nothing to compile these to. No workaround short of modeling the range as two columns and writing the comparison manually, or switching backends.
|
|
42
|
+
|
|
43
|
+
### Quantified comparison operators
|
|
44
|
+
|
|
45
|
+
`eq(any)` / `eq(all)`, `neq(any)` / `neq(all)`, and the `gt`/`gte`/`lt`/`lte` equivalents. Postgres compiles `col=eq(any).{1,2,3}` to `col = ANY(ARRAY[...])`; SQLite has no array type and no quantified form on scalars. Not implemented: use `.in()` for the `eq(any)` case, or switch backends for the general form.
|
|
46
|
+
|
|
47
|
+
## Partial on SQLite
|
|
48
|
+
|
|
49
|
+
### `schema()`
|
|
50
|
+
|
|
51
|
+
Real Postgres multi-schema isn't available on SQLite, but it's not a flat no. On the `sqlite-postgres` driver, schema-qualified DDL is flattened into one physical namespace while PostgREST still records which schema each table came from, so `schema()` (the `Accept-Profile` header) routes correctly. There's no namespace isolation, and the bare `sqlite` driver has no schema handling at all. See [Schemas](/database/schemas).
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### `contains()` / `containedBy()` / `overlaps()`
|
|
55
|
+
|
|
56
|
+
Scalar arrays and shallow objects with scalar values work (`tags=cs.{a,b}`, `meta=cs.{"theme":"dark"}`), matched via `json_each`/`json_extract`. What doesn't work: arrays of objects (`[{a:1}] @> [{a:1}]`) and nested objects in the filter value (`data=cs.{"user":{"id":1}}`), because `json_extract` returns the sub-value as JSON text, which doesn't compare equal to the JS-object bind. `cd`/`ov` also currently require array inputs.
|
|
57
|
+
|
|
58
|
+
### `textSearch()` (all variants: `fts`, `plfts`, `phfts`, `wfts`)
|
|
59
|
+
|
|
60
|
+
SQLite has no FTS5-backed tsvector equivalent wired up here. What runs instead is a LIKE-based lexeme approximation: the query is split into terms and matched with `LIKE`, not real ranking or stemming. Phrase (`plfts`) and websearch (`wfts`) variants are parsed into the same lexeme approximation. Language/dictionary variants and computed-column FTS are limited. Good enough for basic "contains these words" search; not a substitute for Postgres full-text search.
|
|
61
|
+
|
|
62
|
+
### `regexMatch()` / `regexIMatch()`
|
|
63
|
+
|
|
64
|
+
Only simple anchored or literal patterns translate: `^foo`, `bar$`, `^exact$`, plain substrings. These become SQLite `GLOB` (case-sensitive) or `LIKE` (case-insensitive). Character classes, quantifiers, and alternation are not supported: the pattern either matches the simple-case translator or it doesn't get evaluated correctly.
|
|
65
|
+
|
|
66
|
+
### `explain()`
|
|
67
|
+
|
|
68
|
+
Returns the compiled SQL via `application/vnd.pgrst.plan` on both SQLite and Postgres, but real query-plan output (row estimates, actual timing) isn't surfaced on either dialect yet.
|
|
69
|
+
|
|
70
|
+
## Fully works (all backends)
|
|
71
|
+
|
|
72
|
+
- All CRUD: `from`, `select`, `insert`, `update`, `delete`, `upsert`, with `RETURNING`.
|
|
73
|
+
- All comparison filters: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `is`, `isDistinct`.
|
|
74
|
+
- All pattern-matching filters: `like`, `ilike`, `likeAllOf`, `likeAnyOf`, `ilikeAllOf`, `ilikeAnyOf`.
|
|
75
|
+
- Advanced filters: `match`, `or`, `not`, `filter`.
|
|
76
|
+
- Transforms: `order`, `limit`, `range`, `single`, `maybeSingle`.
|
|
77
|
+
- Resource embedding: foreign-key joins (auto-resolved from introspection), `!inner`, spreads (`...`), nested multi-level embeds, and aggregates (`count`, `sum`, `avg`, `min`, `max`).
|
|
78
|
+
- Response/utility methods: `csv()`, `abortSignal()`, `setHeader()`, `throwOnError()`, `maxAffected()`.
|
|
79
|
+
|
|
80
|
+
`geojson()` is not implemented on either backend (requires SpatiaLite or PostGIS, not wired up). `rollback()` is a PostgREST-specific method not implemented on either backend. `returns()` and `overrideTypes()` are TypeScript-only and need no backend support.
|
|
81
|
+
|
|
82
|
+
<Aside type="note">
|
|
83
|
+
Custom media handlers, computed columns backed by PG function metadata, and `SET LOCAL role` / JWT-driven role switching are known gaps that show up in the upstream PostgREST spec suite rather than the `supabase-js` surface. See the skip breakdown in the package's `STATUS.md`.
|
|
84
|
+
</Aside>
|
|
85
|
+
|
|
86
|
+
## See also
|
|
87
|
+
|
|
88
|
+
- [Backends](/database/backends): how to switch driver to get full parity for anything listed above.
|
|
89
|
+
- [Row Level Security](/database/rls): filter-adjacent, but its own set of SQLite caveats.
|
|
90
|
+
- [Compatibility](/compatibility): capability rollup across all services.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Functions & triggers"
|
|
3
|
+
description: "The PL/pgSQL trigger subset supported on SQLite, and what runs unmodified on Postgres backends."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Supabase database functions and triggers are ordinary Postgres features: `CREATE FUNCTION ... LANGUAGE plpgsql` plus `CREATE TRIGGER`. On the SQLite path, Supabase Lite doesn't run PL/pgSQL: it translates a supported subset of trigger function bodies into inline SQLite `CREATE TRIGGER` statements at DDL-translation time. On PGlite/Postgres, full PL/pgSQL runs unmodified. See the [Supabase database functions guide](https://supabase.com/docs/guides/database/functions) and [triggers guide](https://supabase.com/docs/guides/database/postgres/triggers) for the base concepts.
|
|
10
|
+
|
|
11
|
+
<Aside type="caution">
|
|
12
|
+
Only **trigger functions** (`RETURNS TRIGGER`) are translated on SQLite. Standalone/non-trigger functions and `rpc()` calls into them are not supported there. See [Data API divergences](/database/data-api#not-supported-on-sqlite).
|
|
13
|
+
</Aside>
|
|
14
|
+
|
|
15
|
+
## How it works
|
|
16
|
+
|
|
17
|
+
Postgres trigger functions are parsed and stored in a registry. When the corresponding `CREATE TRIGGER` statement is reached, the function body is inlined directly into a SQLite `CREATE TRIGGER`. `SECURITY DEFINER` is silently ignored (SQLite has no privilege model to apply it to).
|
|
18
|
+
|
|
19
|
+
## Supported statement subset (SQLite)
|
|
20
|
+
|
|
21
|
+
| Statement | Example | SQLite translation |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `NEW.col = expr` | `NEW.updated_at = now()` | `UPDATE table SET updated_at = datetime('now') WHERE rowid = NEW.rowid` |
|
|
24
|
+
| `NEW.col := expr` | `NEW.name := upper(NEW.name)` | Same as above |
|
|
25
|
+
| `INSERT INTO ...` | `INSERT INTO profiles (id) VALUES (NEW.id)` | Passed through inside the trigger body |
|
|
26
|
+
| `UPDATE ...` / `DELETE ...` | Any DML | Passed through inside the trigger body |
|
|
27
|
+
| `RETURN NEW` / `RETURN OLD` | Required in Postgres | Not emitted, implicit in SQLite |
|
|
28
|
+
|
|
29
|
+
Multiple `NEW.col = expr` assignments in the same function are merged into a single `UPDATE ... SET` statement.
|
|
30
|
+
|
|
31
|
+
**Trigger options supported:** `BEFORE`/`AFTER` timing, `INSERT`/`UPDATE`/`DELETE` events and combinations, `UPDATE OF col1, col2`, `FOR EACH ROW`.
|
|
32
|
+
|
|
33
|
+
## Not supported on SQLite
|
|
34
|
+
|
|
35
|
+
These throw a descriptive error rather than silently dropping:
|
|
36
|
+
|
|
37
|
+
- `DECLARE` (variable declarations)
|
|
38
|
+
- `IF` / `ELSIF` / `ELSE`
|
|
39
|
+
- `LOOP` (and other iteration constructs)
|
|
40
|
+
- `RAISE`
|
|
41
|
+
- `PERFORM`
|
|
42
|
+
- `SELECT INTO`
|
|
43
|
+
- `EXECUTE`
|
|
44
|
+
- Local variables in general
|
|
45
|
+
- Non-trigger (standalone) functions
|
|
46
|
+
|
|
47
|
+
If your trigger body needs any of these, either restructure it into the supported subset (see the recipes below), or switch to a Postgres backend where full PL/pgSQL runs. See [Backends](/database/backends).
|
|
48
|
+
|
|
49
|
+
## Recipes
|
|
50
|
+
|
|
51
|
+
### `updated_at` timestamp via trigger
|
|
52
|
+
|
|
53
|
+
```sql
|
|
54
|
+
create or replace function set_updated_at() returns trigger language plpgsql as $$
|
|
55
|
+
begin
|
|
56
|
+
new.updated_at = now();
|
|
57
|
+
return new;
|
|
58
|
+
end;
|
|
59
|
+
$$;
|
|
60
|
+
|
|
61
|
+
create trigger set_<thing>_updated_at
|
|
62
|
+
before update on <thing>
|
|
63
|
+
for each row execute function set_updated_at();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The translator inlines `NEW.updated_at = now()` into a SQLite `UPDATE ... SET updated_at = datetime('now')` trigger body.
|
|
67
|
+
|
|
68
|
+
### Profile row on signup (`handle_new_user`)
|
|
69
|
+
|
|
70
|
+
```sql
|
|
71
|
+
create or replace function handle_new_user() returns trigger language plpgsql as $$
|
|
72
|
+
begin
|
|
73
|
+
insert into public.profiles (id, email) values (new.id, new.email);
|
|
74
|
+
return new;
|
|
75
|
+
end;
|
|
76
|
+
$$;
|
|
77
|
+
|
|
78
|
+
create trigger on_auth_user_created
|
|
79
|
+
after insert on auth.users
|
|
80
|
+
for each row execute function handle_new_user();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Supported on all backends: the function body is a single `INSERT`, which passes through unmodified on SQLite and runs as ordinary PL/pgSQL on PGlite/Postgres.
|
|
84
|
+
|
|
85
|
+
## On Postgres backends
|
|
86
|
+
|
|
87
|
+
PGlite and Postgres run the trigger function bodies exactly as written. `DECLARE`, `IF`/`ELSIF`/`ELSE`, `LOOP`, `RAISE`, `PERFORM`, `SELECT INTO`, `EXECUTE`, and standalone functions all work with no restrictions, since it's real PL/pgSQL executed by real Postgres.
|
|
88
|
+
|
|
89
|
+
## See also
|
|
90
|
+
|
|
91
|
+
- [Postgres → SQLite translation](/database/postgres-sqlite-translation): the broader DDL translation mechanism triggers are part of.
|
|
92
|
+
- [Data API divergences](/database/data-api): why `rpc()` (calling standalone functions from the client) isn't available on SQLite.
|
|
93
|
+
- [Backends](/database/backends): switch to `pglite`/`postgres` for full PL/pgSQL support.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Migrations"
|
|
3
|
+
description: "lite migration and lite db commands, the declarative diff flow, and how they differ from supabase db."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
Supabase Lite supports both declarative schemas (`supabase/schemas/*.sql`) and imperative migrations (`supabase/migrations/*.sql`), the same two workflows Supabase supports. Migration files use the same filename format as the Supabase CLI (`<14-digit-timestamp>_<name>.sql`) and the same history table (`supabase_migrations.schema_migrations`), so migration files are portable between the two. See the [Supabase migrations guide](https://supabase.com/docs/guides/deployment/database-migrations) for the base concepts.
|
|
9
|
+
|
|
10
|
+
## Commands
|
|
11
|
+
|
|
12
|
+
<Tabs>
|
|
13
|
+
<TabItem label="migration group">
|
|
14
|
+
| Command | Description |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `lite migration new <name>` | Create an empty migration file in `supabase/migrations/` |
|
|
17
|
+
| `lite migration up` | Apply pending migrations (`--dry-run` lists without applying) |
|
|
18
|
+
| `lite migration list` | Show applied vs pending migrations |
|
|
19
|
+
|
|
20
|
+
`migration down`, `migration repair`, `migration squash`, and `migration fetch` are not registered (🔄 planned).
|
|
21
|
+
</TabItem>
|
|
22
|
+
<TabItem label="db group">
|
|
23
|
+
| Command | Description |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `lite db diff` | `--local` semantics; `-f <name>` emits a pg-DDL migration from the declarative schema diff |
|
|
26
|
+
| `lite db query "<sql>"` | Run a SQL statement against the local DB (renamed from top-level `exec`; supports `--remote`, `--config`) |
|
|
27
|
+
| `lite db translate "<sql>"` | Translate Postgres SQL to the backend dialect (arg or stdin); pipe into `lite db query` to apply |
|
|
28
|
+
| `lite db schema` | `[lite]`-only: print current DB schema; `--diff` compares vs `schemas/*.sql`, `--sql` prints raw `CREATE` statements |
|
|
29
|
+
| `lite db reset` | Drop everything, replay migrations, run seed. Does **not** apply declarative `schema_paths`. |
|
|
30
|
+
|
|
31
|
+
`db push`, `db pull`, `db dump`, `db lint`, `db advisors`, and `db start` are not registered.
|
|
32
|
+
</TabItem>
|
|
33
|
+
</Tabs>
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
lite migration new add_users # supabase/migrations/<ts>_add_users.sql
|
|
37
|
+
# ... edit the file ...
|
|
38
|
+
lite migration up # apply pending migrations
|
|
39
|
+
lite migration list # show applied vs pending
|
|
40
|
+
lite db diff -f tweak # diff schemas/ against applied migrations, emit a new pg-DDL migration
|
|
41
|
+
lite migration up # apply the newly emitted migration
|
|
42
|
+
lite db reset # drop everything, replay migrations, run seed
|
|
43
|
+
cat supabase/seed.sql | lite db translate | lite db query # translate + run ad-hoc SQL
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## The declarative diff flow
|
|
47
|
+
|
|
48
|
+
1. Edit `supabase/schemas/schema.sql` (or the files listed in `[db.migrations].schema_paths`).
|
|
49
|
+
2. Run `lite db diff -f <name>` to compare the live database against the declarative files.
|
|
50
|
+
3. Supabase Lite emits a new migration file under `supabase/migrations/` containing the Postgres DDL needed to close the gap — occasionally more than one, see below.
|
|
51
|
+
4. `lite migration up` applies it (or `lite dev` applies pending migrations automatically on boot, then re-runs the declarative diff).
|
|
52
|
+
|
|
53
|
+
### When a diff emits more than one file
|
|
54
|
+
|
|
55
|
+
A new enum value is unusable until the transaction that added it commits, and each migration file is applied in its own transaction. So exactly two shapes split into `<name>_1.sql`, `<name>_2.sql`, … — a split numbers every file, so there is no unsuffixed file in the set:
|
|
56
|
+
|
|
57
|
+
- **Adding an enum value and using it in the same diff** — e.g. adding `'archived'` to a status enum and a column defaulting to `'archived'`. The `ALTER TYPE` goes in the first file, everything that uses the new value in the second.
|
|
58
|
+
- **Adding more than one value to the same enum in one diff** — one file per added value. Each statement is anchored on the previous value (`ADD VALUE 'c' AFTER 'b'`), so it references a value that isn't visible until the transaction that added it commits.
|
|
59
|
+
|
|
60
|
+
Unrelated changes in the same diff do not cause a split: they are ordered ahead of the `ALTER TYPE` and stay in the first file. Nothing else splits — multi-column type changes, added constraints, and view rebuilds all apply in a single transaction.
|
|
61
|
+
|
|
62
|
+
Migrations and declarative schemas coexist: `lite dev` and the Vite plugin apply pending migrations on boot, then run the declarative diff against `schemas/*.sql`. RLS policies authored directly in migration files are picked up at request time, same as policies from the declarative schema.
|
|
63
|
+
|
|
64
|
+
Destructive deltas (dropped columns/tables, incompatible type changes) aren't auto-emitted: `lite db diff` errors on data-loss rather than generating a lossy migration, and you author those by hand, matching how Supabase's own declarative diff behaves.
|
|
65
|
+
|
|
66
|
+
## Which DDL dialect to write
|
|
67
|
+
|
|
68
|
+
- On `sqlite-postgres`, `pglite`, and `postgres` drivers: write raw Postgres DDL in `supabase/migrations/*.sql`. The runtime translates it on the fly; see [Postgres → SQLite translation](/database/postgres-sqlite-translation).
|
|
69
|
+
- On the bare `sqlite` driver: write SQLite DDL directly in `supabase/sqlite-migrations/*.sql` instead. No translation happens on this path.
|
|
70
|
+
|
|
71
|
+
## How this differs from `supabase db`
|
|
72
|
+
|
|
73
|
+
Supabase Lite's CLI aligns to the upstream `supabase` CLI's command shape (currently tracking v2.98.2), but several `db` subcommands aren't registered because they depend on infrastructure Supabase Lite doesn't have (a separate Postgres container, a linked hosted project with a dashboard, `pg_dump`):
|
|
74
|
+
|
|
75
|
+
| Upstream command | Status in Supabase Lite |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `db push` | Not registered; use `lite cloud deploy` instead |
|
|
78
|
+
| `db pull` | Not registered |
|
|
79
|
+
| `db dump` | Not registered |
|
|
80
|
+
| `db lint` | Not registered |
|
|
81
|
+
| `db advisors` | Not registered |
|
|
82
|
+
| `db start` | Not applicable: Supabase Lite is in-process, no separate DB container to start |
|
|
83
|
+
| `migration down` / `repair` / `squash` / `fetch` | Not registered (planned) |
|
|
84
|
+
|
|
85
|
+
`config push` (pushing `config.toml` to a linked project) is folded into `lite cloud deploy` rather than split out as its own `config` group, until that's worth separating.
|
|
86
|
+
|
|
87
|
+
See [CLI overview](/cli/overview) for the full command reference, including the `cloud` group that replaces some of the management-API surface upstream `supabase` exposes.
|
|
88
|
+
|
|
89
|
+
## See also
|
|
90
|
+
|
|
91
|
+
- [Declarative schemas](/database/schemas): what to write in `supabase/schemas/*.sql`.
|
|
92
|
+
- [Postgres → SQLite translation](/database/postgres-sqlite-translation): the DDL translation mechanism migrations rely on.
|
|
93
|
+
- [CLI overview](/cli/overview): the full `lite` command reference.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Database overview"
|
|
3
|
+
description: "How Supabase Lite's Postgres-shaped Data API maps onto SQLite, PGlite, and Postgres."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside, Card, CardGrid } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Supabase Lite ships a PostgREST-compatible Data API in front of whichever database backend you configure. You write Postgres DDL and call `@supabase/supabase-js` exactly as you would against Supabase; the divergence is in what each backend can execute underneath.
|
|
10
|
+
|
|
11
|
+
Two dimensions matter for every feature on this page:
|
|
12
|
+
|
|
13
|
+
- **Which backend you're on.** SQLite (via `bun:sqlite`, `node:sqlite`, `@sqlite.org/sqlite-wasm`, or Cloudflare D1/DO) is the default, zero-dependency path. PGlite and Postgres are full-parity alternatives selected in `supabase/config.toml`. See [Backends](/database/backends).
|
|
14
|
+
- **Which capability you're using.** Core CRUD, comparison/pattern filters, resource embedding, transforms, and RLS all work the same on every backend. `rpc()`, range types, quantified comparisons, real full-text search, and regex are Postgres/PGlite-only.
|
|
15
|
+
|
|
16
|
+
<Aside type="note">
|
|
17
|
+
Counts and per-method status live in the package's own `STATUS.md` and update on every `npm install`. This page and its siblings describe the shape of the divergence, not exact totals. See [Compatibility](/compatibility) for the rollup.
|
|
18
|
+
</Aside>
|
|
19
|
+
|
|
20
|
+
## What holds across every backend
|
|
21
|
+
|
|
22
|
+
- Full CRUD (`select`, `insert`, `update`, `delete`, `upsert`) with `RETURNING`.
|
|
23
|
+
- All comparison filters (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `notIn`, `is`, `isDistinct`) and all pattern-matching filters (`like`, `ilike`, and their quantified `AllOf`/`AnyOf` forms).
|
|
24
|
+
- Resource embedding: foreign-key joins, `!inner`, spreads, nested embeds, and aggregates (`count`, `sum`, `avg`, `min`, `max`).
|
|
25
|
+
- Transforms: `order`, `limit`, `range`, `single`, `maybeSingle`.
|
|
26
|
+
- Row Level Security: default-deny, `USING`/`WITH CHECK`, permissive/restrictive policies, per-command targeting, role targeting, `auth.uid()`/`auth.jwt()`.
|
|
27
|
+
|
|
28
|
+
## Where it splits by backend
|
|
29
|
+
|
|
30
|
+
SQLite has no arrays, ranges, regex engine, or stored-procedure model, so a handful of `supabase-js` methods either don't exist there or run in a reduced form: `rpc()`, embedded dotted-path filters, range operators, quantified comparisons, real full-text search, and regex matching. See [Data API divergences](/database/data-api) for the full list and workarounds.
|
|
31
|
+
|
|
32
|
+
Schema authoring, migrations, and RLS enforcement also have SQLite-specific mechanics worth knowing before you hit them in production:
|
|
33
|
+
|
|
34
|
+
- [Postgres → SQLite translation](/database/postgres-sqlite-translation): how DDL gets rewritten, which column defaults are honored, and the exact error you'll see for unsupported `CHECK`/`DEFAULT` functions.
|
|
35
|
+
- [Row Level Security](/database/rls): works on every backend, but SQLite enforces it at the application layer with specific gaps (`WITH CHECK` subqueries, `DEFAULT auth.uid()`).
|
|
36
|
+
- [Declarative schemas](/database/schemas) and [migrations](/database/migrations): the same `supabase/schemas/*.sql` and `supabase/migrations/*.sql` workflow as Supabase, with SQLite's single-namespace constraint.
|
|
37
|
+
- [Functions & triggers](/database/functions-triggers): a supported subset of PL/pgSQL trigger bodies on SQLite; full PL/pgSQL on Postgres backends.
|
|
38
|
+
|
|
39
|
+
For the parts of Supabase's database story that behave identically here (the general architecture, product terminology, and Postgres fundamentals), see the [Supabase Database overview](https://supabase.com/docs/guides/database/overview). This site only documents where Supabase Lite diverges.
|
|
40
|
+
|
|
41
|
+
<CardGrid>
|
|
42
|
+
<Card title="Backends">
|
|
43
|
+
SQLite drivers vs PGlite/Postgres: how to pick, how to switch. [Read more →](/database/backends/)
|
|
44
|
+
</Card>
|
|
45
|
+
<Card title="Data API divergences">
|
|
46
|
+
What's unsupported, partial, and fully working on SQLite vs Postgres. [Read more →](/database/data-api/)
|
|
47
|
+
</Card>
|
|
48
|
+
<Card title="Row Level Security">
|
|
49
|
+
Enforcement model per backend and SQLite-specific caveats. [Read more →](/database/rls/)
|
|
50
|
+
</Card>
|
|
51
|
+
<Card title="Declarative schemas">
|
|
52
|
+
Writing Postgres DDL in `supabase/schemas/*.sql`. [Read more →](/database/schemas/)
|
|
53
|
+
</Card>
|
|
54
|
+
<Card title="Migrations">
|
|
55
|
+
`lite migration` / `lite db` commands vs upstream `supabase db`. [Read more →](/database/migrations/)
|
|
56
|
+
</Card>
|
|
57
|
+
<Card title="Functions & triggers">
|
|
58
|
+
The PL/pgSQL trigger subset supported on SQLite. [Read more →](/database/functions-triggers/)
|
|
59
|
+
</Card>
|
|
60
|
+
<Card title="Postgres → SQLite translation">
|
|
61
|
+
The DDL translation mechanism, defaults, and CHECK constraint rules. [Read more →](/database/postgres-sqlite-translation/)
|
|
62
|
+
</Card>
|
|
63
|
+
<Card title="Compatibility">
|
|
64
|
+
Full capability rollup across services. [Read more →](/compatibility/)
|
|
65
|
+
</Card>
|
|
66
|
+
</CardGrid>
|