@supabase/lite 0.8.1-next.2 → 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,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Vite plugin"
|
|
3
|
+
description: "Run Supabase Lite in-process inside the Vite dev server. The recommended path for Vite frontends."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
If your frontend uses Vite, this is the recommended way to run Supabase Lite: no separate CLI process, no Docker, no proxy config. The `@supabase/lite/vite` plugin runs the backend inline inside the Vite dev server, so one process serves both your app and the API.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
// vite.config.ts
|
|
12
|
+
import { defineConfig } from "vite";
|
|
13
|
+
import { supalite } from "@supabase/lite/vite";
|
|
14
|
+
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
plugins: [supalite()],
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
<Aside type="caution">
|
|
21
|
+
Don't run `lite dev` or `lite start` at the same time as this plugin. It isn't a port conflict (the CLI binds `[api].port` from `config.toml`; the plugin rides on the Vite dev server's port). The issue is two backends driving the same `supabase/` project and SQLite file, racing migrations and schema watchers. Pick one process model per project, see [Running Supabase Lite](/running).
|
|
22
|
+
</Aside>
|
|
23
|
+
|
|
24
|
+
## What it does
|
|
25
|
+
|
|
26
|
+
- Auto-resolves `./supabase/config.toml` from the project root.
|
|
27
|
+
- Applies pending imperative migrations, then the declarative schema diff, on boot.
|
|
28
|
+
- Watches `schemas/*.sql` (and the migrations directory) for hot-reload during `vite`/`vite dev`.
|
|
29
|
+
- Mounts `/auth/v1`, `/rest/v1`, and `/_system` as middleware on the Vite dev/preview server.
|
|
30
|
+
- Injects `VITE_SUPABASE_URL` (the current browser origin, via `window.location.origin`) and the project's resolved `sb_publishable_*` key as `VITE_SUPABASE_ANON_KEY` into `import.meta.env`, so the canonical client snippet works with zero `.env` setup, even with key enforcement on.
|
|
31
|
+
|
|
32
|
+
<Aside type="caution">
|
|
33
|
+
`vite preview` mounts the API and runs boot-time migrations, but does **not** watch schemas (it simulates production). `vite build` and any standalone production server do not mount the API at all. Use `lite start`, hosted Supabase, or an embedded app there.
|
|
34
|
+
</Aside>
|
|
35
|
+
|
|
36
|
+
## Client setup
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createClient } from "@supabase/supabase-js";
|
|
40
|
+
|
|
41
|
+
const client = createClient(
|
|
42
|
+
import.meta.env.VITE_SUPABASE_URL,
|
|
43
|
+
import.meta.env.VITE_SUPABASE_ANON_KEY,
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Equivalently, since the plugin's default URL is always the current origin:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const client = createClient(window.location.origin, "<sb_publishable_...>");
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The plugin resolves the project's real `auth.publishable_key` (see [API keys](/auth/overview#api-keys)) and injects it as `VITE_SUPABASE_ANON_KEY`, so a `lite init`'d project works with zero `.env` setup even with key enforcement on. The placeholder `"sb-lite-anon-key"` is only used as a fallback when no project/key is found.
|
|
54
|
+
|
|
55
|
+
A `.env` value for either `VITE_SUPABASE_URL` or `VITE_SUPABASE_ANON_KEY` always overrides the plugin's injected default. The plugin only fills in what you haven't set, and it resolves your `root`/`envDir`/`envPrefix` the same way Vite itself does, so a value that Vite would expose is a value the plugin sees.
|
|
56
|
+
|
|
57
|
+
## Options
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
supalite({
|
|
61
|
+
config: "./supabase/config.toml",
|
|
62
|
+
migrateOnBoot: true,
|
|
63
|
+
watchSchema: true,
|
|
64
|
+
forceSchema: false,
|
|
65
|
+
initOnBoot: true,
|
|
66
|
+
prefixes: ["/auth/v1", "/rest/v1", "/_system"],
|
|
67
|
+
admin: true,
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Option | Type | Default | Description |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| `config` | string | auto-resolved `./supabase/config.toml` | Path to the project's `config.toml`. Defaults to auto-resolving `./supabase/config.toml` relative to where Vite runs. |
|
|
74
|
+
| `migrateOnBoot` | boolean | `true` | Apply pending imperative migrations, then run the declarative schema diff, when the dev/preview server starts. |
|
|
75
|
+
| `watchSchema` | boolean | `true` | Watch `schemas/*.sql` and the migrations directory for changes and hot-reload the schema. Only takes effect during `vite`/`vite dev`; `vite preview` never watches, regardless of this option. |
|
|
76
|
+
| `forceSchema` | boolean | `false` | Allow the declarative schema diff to apply changes that would otherwise be blocked as data-loss. Logs a warning on boot when enabled. |
|
|
77
|
+
| `initOnBoot` | boolean | `true` | Scaffold the initial `supabase/` structure if it doesn't exist yet, equivalent to `lite init`, before starting. |
|
|
78
|
+
| `prefixes` | string[] | `["/auth/v1", "/rest/v1", "/_system"]` | Which path prefixes the plugin mounts on the Vite server. Only override this if you need to move the API off its default paths. |
|
|
79
|
+
| `admin` | boolean | `true` | [Admin mode](/running#admin-mode): serve keyless, same-origin, loopback `/rest/v1` requests as `service_role`. (Admin mode also covers `/storage/v1`, but the plugin does not mount that prefix by default — add it to `prefixes` first.) Only takes effect during `vite`/`vite dev`; `vite preview` never enables it, regardless of this option. Set `false` to keep key enforcement on every request while developing. An `admin` value in `config.toml` is used only when this option is unset. |
|
|
80
|
+
|
|
81
|
+
## Related
|
|
82
|
+
|
|
83
|
+
- [Running Supabase Lite](/running): how this compares to `lite dev`/`lite start`/embedding.
|
|
84
|
+
- [Embedded / programmatic](/integrations/embedded): the same boot sequence, driven manually instead of by the plugin.
|
|
85
|
+
- Upstream: [Supabase local development](https://supabase.com/docs/guides/local-development), the Docker-based equivalent this plugin replaces for Vite apps.
|
package/docs/llms.txt
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Supabase Lite docs
|
|
2
|
+
|
|
3
|
+
Bundled with @supabase/lite 0.9.1-next.1. Same content as https://docs.lite.dev, which tracks the latest release.
|
|
4
|
+
Files are MDX source (Astro Starlight). Site path -> file: `/` -> `index.mdx`, `/database/rls` -> `database/rls.mdx`.
|
|
5
|
+
|
|
6
|
+
## Start
|
|
7
|
+
|
|
8
|
+
- [Introduction](index.mdx): What Supabase Lite is, what's supported today, and how it relates to hosted Supabase.
|
|
9
|
+
- [Quickstart](quickstart.mdx): Install Supabase Lite, scaffold a project, write a schema, and run your first query.
|
|
10
|
+
- [Compatibility](compatibility.mdx): Capability-level support matrix for the Data API, Auth, Storage, RLS, Realtime, and Edge Functions across SQLite, PGlite, and Postgres.
|
|
11
|
+
- [Running Supabase Lite](running.mdx): Choose between the Vite plugin, lite dev, lite start, and embedded/programmatic usage.
|
|
12
|
+
- [Upgrading to Supabase](upgrade.mdx): Migrate a Supabase Lite project to hosted or local Supabase with lite upgrade.
|
|
13
|
+
|
|
14
|
+
## Database
|
|
15
|
+
|
|
16
|
+
- [Database overview](database/overview.mdx): How Supabase Lite's Postgres-shaped Data API maps onto SQLite, PGlite, and Postgres.
|
|
17
|
+
- [Backends](database/backends.mdx): SQLite drivers vs PGlite/Postgres: how Supabase Lite picks a database, and how to switch.
|
|
18
|
+
- [Data API divergences](database/data-api.mdx): Where the PostgREST-compatible Data API and supabase-js diverge on SQLite, and the workarounds.
|
|
19
|
+
- [Row Level Security](database/rls.mdx): RLS works on every Supabase Lite backend; SQLite enforces it at the application layer with specific caveats.
|
|
20
|
+
- [Declarative schemas](database/schemas.mdx): Writing Postgres DDL in supabase/schemas/*.sql, and how it maps onto SQLite's single-namespace model.
|
|
21
|
+
- [Migrations](database/migrations.mdx): lite migration and lite db commands, the declarative diff flow, and how they differ from supabase db.
|
|
22
|
+
- [Functions & triggers](database/functions-triggers.mdx): The PL/pgSQL trigger subset supported on SQLite, and what runs unmodified on Postgres backends.
|
|
23
|
+
- [Postgres → SQLite translation](database/postgres-sqlite-translation.mdx): How Supabase Lite auto-translates Postgres DDL to SQLite, and the exact errors you'll see when something isn't supported.
|
|
24
|
+
|
|
25
|
+
## Auth
|
|
26
|
+
|
|
27
|
+
- [Auth overview](auth/overview.mdx): GoTrue-compatible Auth API for @supabase/lite: what's implemented, what's planned, and how it fits into supabase-js.
|
|
28
|
+
- [Supported auth flows](auth/supported-flows.mdx): The 13 GoTrue-compatible Auth endpoints Supabase Lite implements, with supabase-js examples.
|
|
29
|
+
- [Email delivery & templates](auth/email.mdx): Configure the email driver, verification links, and customizable transactional email templates for Supabase Lite Auth.
|
|
30
|
+
- [Auth: not supported](auth/not-supported.mdx): Anonymous sign-in, manual identity linking, the admin API, MFA, and OAuth providers beyond github/google are not implemented yet. What's planned vs. not planned, and the hosted-Supabase workaround.
|
|
31
|
+
|
|
32
|
+
## Storage
|
|
33
|
+
|
|
34
|
+
- [Storage overview](storage/overview.mdx): Storage API for @supabase/lite: experimental flag, endpoint coverage, and supabase-js parity.
|
|
35
|
+
- [Storage adapters](storage/adapters.mdx): Pluggable storage backends (filesystem, S3-compatible) and transformation adapters (Noop, Sharp, Cloudflare) for Supabase Lite Storage.
|
|
36
|
+
- [Storage limitations](storage/limitations.mdx): What's not yet implemented in Supabase Lite Storage: access control, RLS on objects, TUS uploads, webhooks, and the S3-compatible server protocol.
|
|
37
|
+
|
|
38
|
+
## Integrations
|
|
39
|
+
|
|
40
|
+
- [Vite plugin](integrations/vite.mdx): Run Supabase Lite in-process inside the Vite dev server. The recommended path for Vite frontends.
|
|
41
|
+
- [Embedded / programmatic](integrations/embedded.mdx): Use the App class directly in Bun, Node, browser, or edge runtimes, without the CLI.
|
|
42
|
+
- [Framework guides](integrations/frameworks.mdx): Running Supabase Lite inside Next.js, Cloudflare Workers, and Docker.
|
|
43
|
+
|
|
44
|
+
## CLI
|
|
45
|
+
|
|
46
|
+
- [CLI overview](cli/overview.mdx): The lite CLI versus the supabase CLI: parity, gaps, and what's still experimental.
|
|
47
|
+
- [Telemetry](cli/telemetry.mdx): The lite CLI sends anonymous usage telemetry by default. How to disable it.
|
|
48
|
+
|
|
49
|
+
## Other
|
|
50
|
+
|
|
51
|
+
- [Edge Functions](other/edge-functions.mdx): Supabase Edge Functions (Deno runtime) are not supported in @supabase/lite. Run a regular server endpoint instead.
|
|
52
|
+
- [Realtime](other/realtime.mdx): Supabase Realtime (channels, presence, broadcast, Postgres Changes) is not implemented in @supabase/lite yet.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Edge Functions"
|
|
3
|
+
description: "Supabase Edge Functions (Deno runtime) are not supported in @supabase/lite. Run a regular server endpoint instead."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
<Aside type="caution">
|
|
9
|
+
Edge Functions are not supported. Supabase Lite does not bundle a Deno or edge runtime, and there is no `/functions/v1/*` route.
|
|
10
|
+
</Aside>
|
|
11
|
+
|
|
12
|
+
A config schema for functions exists in `app/src/config/functions.ts` (per-function JWT verification, entrypoints), but nothing executes against it: `supabase/functions/*` in your project is not picked up or served by Supabase Lite.
|
|
13
|
+
|
|
14
|
+
## Workaround
|
|
15
|
+
|
|
16
|
+
Supabase Lite is a plain HTTP server (`app.fetch`), so anything you'd put in an Edge Function can live in a normal server endpoint instead, called directly from your client:
|
|
17
|
+
|
|
18
|
+
- A [Hono](https://hono.dev/) or Express route mounted alongside your app
|
|
19
|
+
- A Next.js App Router route handler
|
|
20
|
+
- Vite middleware, in the same process as the [Vite plugin](/integrations/vite)
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// Instead of supabase.functions.invoke("my-function", { body }):
|
|
24
|
+
const res = await fetch("/api/my-function", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
body: JSON.stringify(body),
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Since Supabase Lite already runs your Data API and Auth in-process (`app.fetch`), a hand-rolled endpoint has direct access to `app.getClient()` for database/auth calls without an extra network hop. See [Embedded / programmatic usage](/integrations/embedded) for wiring that up.
|
|
31
|
+
|
|
32
|
+
If you specifically need Deno-compatible Edge Functions (for parity with a production Supabase project, or because you rely on Deno-only APIs), run those against hosted Supabase and keep the rest of your app on Supabase Lite.
|
|
33
|
+
|
|
34
|
+
For the Edge Functions model this replaces, see the [Supabase Edge Functions docs](https://supabase.com/docs/guides/functions). See [Compatibility](/compatibility) for how this tracks against other services.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Realtime"
|
|
3
|
+
description: "Supabase Realtime (channels, presence, broadcast, Postgres Changes) is not implemented in @supabase/lite yet."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
<Aside type="caution">
|
|
9
|
+
Realtime is not implemented. There is no WebSocket server, no channels, and no Postgres Changes stream in Supabase Lite yet.
|
|
10
|
+
</Aside>
|
|
11
|
+
|
|
12
|
+
A config schema for Realtime exists in `app/src/config/realtime.ts`, but it isn't wired to any runtime behavior. Setting `[realtime]` keys in `config.toml` has no effect today. Calling `supabase.channel(...)`, `.on("postgres_changes", ...)`, presence, or broadcast against a Supabase Lite instance will not connect to anything on the server side.
|
|
13
|
+
|
|
14
|
+
## Workaround
|
|
15
|
+
|
|
16
|
+
Run the realtime-dependent parts of your app against hosted Supabase. Supabase Lite can still serve the Data API and Auth for the rest of the app; there's no requirement to run a single backend for every product.
|
|
17
|
+
|
|
18
|
+
## What it would look like
|
|
19
|
+
|
|
20
|
+
When implemented, Realtime would need to cover the same three primitives upstream does: Postgres Changes (streaming row-level INSERT/UPDATE/DELETE events), Broadcast (ephemeral pub/sub over a channel), and Presence (shared client state per channel). None of this exists yet, so check `STATUS.md` in the installed package for current status before building around an assumed timeline.
|
|
21
|
+
|
|
22
|
+
For the concepts and client API this would eventually support unchanged, see the [Supabase Realtime docs](https://supabase.com/docs/guides/realtime). See [Compatibility](/compatibility) for how Realtime tracks against everything else.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Quickstart"
|
|
3
|
+
description: "Install Supabase Lite, scaffold a project, write a schema, and run your first query."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
This walks through the minimal path: install, scaffold, write a schema, run a server, query it with `supabase-js`. For the general Supabase local-dev flow this mirrors, see the [Supabase local development guide](https://supabase.com/docs/guides/local-development).
|
|
9
|
+
|
|
10
|
+
<Steps>
|
|
11
|
+
|
|
12
|
+
1. **Install**
|
|
13
|
+
|
|
14
|
+
Install both `@supabase/lite` and `@supabase/supabase-js`.
|
|
15
|
+
|
|
16
|
+
<Tabs sync="pkg-manager">
|
|
17
|
+
<TabItem label="bun">
|
|
18
|
+
```bash
|
|
19
|
+
bun add @supabase/lite @supabase/supabase-js
|
|
20
|
+
```
|
|
21
|
+
</TabItem>
|
|
22
|
+
<TabItem label="npm">
|
|
23
|
+
```
|
|
24
|
+
npm install @supabase/lite @supabase/supabase-js
|
|
25
|
+
```
|
|
26
|
+
</TabItem>
|
|
27
|
+
<TabItem label="pnpm">
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add @supabase/lite @supabase/supabase-js
|
|
30
|
+
```
|
|
31
|
+
</TabItem>
|
|
32
|
+
</Tabs>
|
|
33
|
+
|
|
34
|
+
Add the `-g` flag if you want the `lite` CLI available system-wide instead of per-project.
|
|
35
|
+
|
|
36
|
+
1. **Scaffold a project**
|
|
37
|
+
|
|
38
|
+
<Tabs sync="pkg-manager">
|
|
39
|
+
<TabItem label="bun">
|
|
40
|
+
```bash
|
|
41
|
+
bunx lite init
|
|
42
|
+
```
|
|
43
|
+
</TabItem>
|
|
44
|
+
<TabItem label="npm">
|
|
45
|
+
```bash
|
|
46
|
+
npx lite init
|
|
47
|
+
```
|
|
48
|
+
</TabItem>
|
|
49
|
+
<TabItem label="pnpm">
|
|
50
|
+
```bash
|
|
51
|
+
pnpm exec lite init
|
|
52
|
+
```
|
|
53
|
+
</TabItem>
|
|
54
|
+
</Tabs>
|
|
55
|
+
|
|
56
|
+
This creates a Supabase-compatible `supabase/` directory: `config.toml`, `schemas/schema.sql`, `seed.sql`, and a git-ignored `.temp/data.db` SQLite file.
|
|
57
|
+
|
|
58
|
+
`lite dev` scaffolds the same structure on boot if it's missing, so you can skip straight to it in an empty directory. `lite start` requires the scaffold to exist — run `init` first.
|
|
59
|
+
|
|
60
|
+
1. **Write your schema**
|
|
61
|
+
|
|
62
|
+
Write plain Postgres DDL in `supabase/schemas/schema.sql`. On the SQLite path it's translated automatically (`SERIAL` → `INTEGER PRIMARY KEY AUTOINCREMENT`, `NOW()` → `datetime('now')`, and so on).
|
|
63
|
+
|
|
64
|
+
A small per-user todos example with RLS enabled:
|
|
65
|
+
|
|
66
|
+
```sql
|
|
67
|
+
create table todos (
|
|
68
|
+
id uuid primary key default gen_random_uuid(),
|
|
69
|
+
user_id uuid not null references auth.users(id) on delete cascade,
|
|
70
|
+
task text not null,
|
|
71
|
+
is_complete boolean not null default false,
|
|
72
|
+
created_at timestamptz not null default now()
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
alter table todos enable row level security;
|
|
76
|
+
|
|
77
|
+
create policy "select own todos" on todos for select to authenticated using (auth.uid() = user_id);
|
|
78
|
+
create policy "insert own todos" on todos for insert to authenticated with check (auth.uid() = user_id);
|
|
79
|
+
create policy "update own todos" on todos for update to authenticated using (auth.uid() = user_id) with check (auth.uid() = user_id);
|
|
80
|
+
create policy "delete own todos" on todos for delete to authenticated using (auth.uid() = user_id);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Currently, default values using functions support is limited, therefore `DEFAULT auth.uid()` is not supported on the SQLite path. You must supply `user_id` by the client on insert; the `WITH CHECK` policy enforces ownership server-side. The `PATTERNS.md` file shipped in the package has more recipes.
|
|
84
|
+
|
|
85
|
+
1. **Pick how you run it**
|
|
86
|
+
|
|
87
|
+
If your frontend uses Vite, use the [Vite plugin](/integrations/vite): it runs Supabase Lite inline in the Vite dev server, no separate process. Otherwise, use the `lite` CLI directly: see [Running Supabase Lite](/running) to choose between `lite dev` (auto schema-reload) and `lite start` (no watch, CI/prod-like).
|
|
88
|
+
|
|
89
|
+
<Tabs sync="pkg-manager">
|
|
90
|
+
<TabItem label="bun">
|
|
91
|
+
```bash
|
|
92
|
+
bunx lite dev
|
|
93
|
+
```
|
|
94
|
+
</TabItem>
|
|
95
|
+
<TabItem label="npm">
|
|
96
|
+
```bash
|
|
97
|
+
npx lite dev
|
|
98
|
+
```
|
|
99
|
+
</TabItem>
|
|
100
|
+
<TabItem label="pnpm">
|
|
101
|
+
```bash
|
|
102
|
+
pnpm exec lite dev
|
|
103
|
+
```
|
|
104
|
+
</TabItem>
|
|
105
|
+
</Tabs>
|
|
106
|
+
|
|
107
|
+
The API is now running at `http://localhost:54321`. `lite init` also generated a publishable/secret API key pair into root `.env` and printed them.
|
|
108
|
+
|
|
109
|
+
1. **Create a client**
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { createClient } from "@supabase/supabase-js";
|
|
113
|
+
|
|
114
|
+
const supabase = createClient(
|
|
115
|
+
"http://localhost:54321",
|
|
116
|
+
"<sb_publishable_...>"
|
|
117
|
+
);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use the printed `sb_publishable_*` key as the anon key. If no keys are configured, `/rest/v1`/`/auth/v1` accept any/no `apikey` (unchanged old behavior). See [API keys](/auth/overview#api-keys).
|
|
121
|
+
|
|
122
|
+
If you're using the [Vite plugin](/integrations/vite) instead, the plugin injects `VITE_SUPABASE_URL` (`window.location.origin`) and a dev `VITE_SUPABASE_ANON_KEY`, so the canonical form works with no manual setup:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { createClient } from "@supabase/supabase-js";
|
|
126
|
+
|
|
127
|
+
const supabase = createClient(
|
|
128
|
+
import.meta.env.VITE_SUPABASE_URL,
|
|
129
|
+
import.meta.env.VITE_SUPABASE_ANON_KEY,
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
1. **Run a query**
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
137
|
+
|
|
138
|
+
await supabase.from("todos").insert({
|
|
139
|
+
user_id: session.user.id,
|
|
140
|
+
task: "Ship the quickstart",
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const { data, error } = await supabase.from("todos").select("*");
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This is standard `supabase-js`, no Supabase Lite-specific API. See [Compatibility](/compatibility) for what else is supported.
|
|
147
|
+
|
|
148
|
+
</Steps>
|
|
149
|
+
|
|
150
|
+
For the full Supabase quickstart flow (project structure, general CLI usage) that this mirrors, see the [Supabase local development guide](https://supabase.com/docs/guides/local-development).
|
package/docs/running.mdx
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Running Supabase Lite"
|
|
3
|
+
description: "Choose between the Vite plugin, lite dev, lite start, and embedded/programmatic usage."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
How you run Supabase Lite is a Supabase Lite-specific concept with no direct Supabase equivalent: since there's no Docker stack, "running Supabase locally" (see the [Supabase local development guide](https://supabase.com/docs/guides/local-development)) becomes a choice between running an in-process plugin, a small CLI server, or embedding the app directly in your own runtime.
|
|
7
|
+
|
|
8
|
+
## Options at a glance
|
|
9
|
+
|
|
10
|
+
| Mode | Process model | Schema reload | Best for |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| [Vite plugin](/integrations/vite) | In-process, mounted on the Vite dev server | Watches `schemas/*.sql` in `vite`/`vite dev`; not in `vite preview` or `vite build` | Any Vite frontend (React/Vue/Svelte/…). Recommended default if you're on Vite. |
|
|
13
|
+
| `lite dev` | Separate process | Watches `schemas/*.sql`, auto-applies on change | Non-Vite apps during active development |
|
|
14
|
+
| `lite start` | Separate process | None: no watch, no auto-migrate | CI, staging, or anything that should behave like production |
|
|
15
|
+
| [Embedded / programmatic](/integrations/embedded) | In-process, inside your own Bun/Node/edge runtime | Manual: you call `createMigrator(...).migrate()` yourself | Custom servers, edge functions, or when you need full control over boot sequence |
|
|
16
|
+
|
|
17
|
+
## Vite plugin
|
|
18
|
+
|
|
19
|
+
If your frontend uses Vite, this is the recommended path: skip the separate CLI process entirely. The `@supabase/lite/vite` plugin mounts `/auth/v1`, `/rest/v1`, and `/_system` directly on the Vite dev server, so one process serves both your app and the API.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// vite.config.ts
|
|
23
|
+
import { defineConfig } from "vite";
|
|
24
|
+
import { supalite } from "@supabase/lite/vite";
|
|
25
|
+
|
|
26
|
+
export default defineConfig({
|
|
27
|
+
plugins: [supalite()],
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Active in `vite` / `vite dev` (watches schemas, hot-reloads) and `vite preview` (mounts the API and runs boot migrations, but does not watch schemas, it simulates production). `vite build` and any standalone production server do not mount the API; use `lite start`, hosted Supabase, or an equivalent there.
|
|
32
|
+
|
|
33
|
+
Full setup and env-var injection details: [Vite integration](/integrations/vite).
|
|
34
|
+
|
|
35
|
+
## `lite dev`
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
lite dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Starts the API server as its own process and watches `supabase/schemas/*.sql`, re-applying the schema automatically on every change. Use this for non-Vite apps (plain Node/Bun backends, mobile clients hitting a local API, etc.) during active development.
|
|
42
|
+
|
|
43
|
+
By default, auth emails (signup confirmation, magic link, password recovery, and so on) are printed to this server console rather than actually sent. See [Email delivery & templates](/auth/email).
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
lite db reset --hard # delete the DB file, replay migrations + seed
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## `lite start`
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
lite start
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Starts the API server with no file watching and no auto-migration. This is the closest Supabase Lite gets to a production-like posture: you control exactly when migrations run (`lite migration up`, `lite db reset`), and the server won't silently reapply schema changes. Use this for CI pipelines and any environment meant to behave like production.
|
|
56
|
+
|
|
57
|
+
On the `sqlite-postgres` driver, RLS and schema metadata is written to `supabase/.temp/.deparse-cache.json` when the declarative schema translates (`lite dev`, the Vite plugin), on every `lite db reset`, and on `lite migration up` in a migrations-only project (in a project that also has `supabase/schemas/*.sql`, `migration up` deliberately leaves the declarative snapshot alone). `lite start` loads this cache at boot to enforce RLS without reparsing SQL. If the file is missing or stale, a migrations-only project recalculates from the applied migration history — never from migration files that haven't been run. If nothing recovers and the database has RLS-enabled tables, `lite start` exits with an error instead of serving with RLS silently off.
|
|
58
|
+
|
|
59
|
+
`lite start` is the migrations workflow, so it never applies `supabase/schemas/*.sql`. A declarative project starts fine while the cache from its last `lite dev` (or Vite plugin) run is still valid; without a valid cache it is always refused, with no exceptions. `lite start` will not re-derive RLS from schema files it cannot prove were applied, and it will not substitute migration-only metadata for them either. Keep developing with `lite dev`, which applies the schema and rewrites the cache, or ship the schema as a migration.
|
|
60
|
+
|
|
61
|
+
`lite db diff -f <name>` then `lite db reset` is the transition that establishes migration authority. The generated migration carries your RLS (`ALTER TABLE ... ENABLE ROW LEVEL SECURITY` and `CREATE POLICY`) along with the tables, and `lite db reset` is destructive: it replays the migrations onto a fresh database, so afterwards the migration-derived metadata describes that database exactly and is always persisted, and `lite start` boots again. The flip side is that `lite db reset` on a project with un-diffed declarative changes adopts **only** the migration state — anything `schemas/*.sql` declares that you never captured, policies included, is not in the reset database. Run `lite db diff -f <name>` first; reset warns when it sees pending declarative changes. `lite migration up` is not the transition: it is non-destructive, so the generated migration re-creates objects the declarative apply already created and fails against the live development database, and it deliberately never overwrites the declarative snapshot on disk.
|
|
62
|
+
|
|
63
|
+
## Admin mode
|
|
64
|
+
|
|
65
|
+
`lite dev`, `lite start`, and the Vite dev server run with **admin mode on**. A request that arrives with no credential at all (no `apikey` header or query parameter, no `Authorization` header) is served as `service_role`, so a local admin UI like the built-in studio can read and edit any table without a secret key ever reaching the browser. This mirrors self-hosted Supabase Studio, where the Next.js server holds the service key and does the privileged work on the client's behalf.
|
|
66
|
+
|
|
67
|
+
Elevation is deliberately narrow. A request is only elevated when all of these hold:
|
|
68
|
+
|
|
69
|
+
- the path is under `/rest/v1` or `/storage/v1` (`/auth/v1` is never elevated). The Vite plugin does not mount `/storage/v1` by default, so there it's `/rest/v1` only
|
|
70
|
+
- it carries no `apikey` and no `Authorization`
|
|
71
|
+
- it is same-origin, or has no `Origin` header at all (so `curl` works, but another website open in your browser does not)
|
|
72
|
+
- it arrived from a loopback socket **and** names a loopback host. Both are required: the peer address stops a machine on your network spoofing `Host: localhost` (the CLI listens on all interfaces), and the hostname stops DNS rebinding, where a hostile page re-resolves its own domain to `127.0.0.1` so the socket really is loopback while `Host` and `Origin` stay theirs
|
|
73
|
+
|
|
74
|
+
Anything else falls through to normal [API key enforcement](/auth/overview#api-keys).
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
lite start --no-admin # off: keyless requests are no longer elevated
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Two things to know:
|
|
81
|
+
|
|
82
|
+
1. **Keyless traffic does not go through RLS while admin mode is on.** To exercise your policies, send an `apikey` — the publishable key for `anon`, or the publishable key **plus** `Authorization: Bearer <user JWT>` for `authenticated`. Those requests are never elevated, so both roles behave exactly as they do in production. That is the whole reason elevation is credential-aware rather than blanket. A bearer token on its own is not enough: with keys configured, a request without an `apikey` is rejected before RLS is reached (401 `UNAUTHORIZED_MISSING_API_KEY`), matching upstream.
|
|
83
|
+
2. **"It runs on my machine" is not per-request trust.** The CLI binds `0.0.0.0`, and any page open in your browser can reach `localhost`. The same-origin and loopback-socket checks are what keep admin mode from being a way to read your local database from a web page or from another machine on your network. Admin mode is for local development only; it is off by default in the embedded/programmatic API and in `vite preview`.
|
|
84
|
+
|
|
85
|
+
Precedence, when several places have an opinion: an explicit `--no-admin` (or the plugin's `admin` option) wins, then `options.server.admin` in `config.toml`, then the launcher's default. So a config file can opt a project out of admin mode entirely, but it can never re-enable it after you passed `--no-admin`.
|
|
86
|
+
|
|
87
|
+
Embedding the `App` yourself is the one case where only the hostname check applies, because there is no socket the library owns. Only set `options.server.admin` on a server you know is bound to loopback.
|
|
88
|
+
|
|
89
|
+
With admin mode off, the bundled studio connects with the publishable key instead and shows you what `anon` can see under RLS, with a banner saying so — it stays usable, just scoped.
|
|
90
|
+
|
|
91
|
+
## Embedded / programmatic
|
|
92
|
+
|
|
93
|
+
For full control, skip the CLI entirely and embed the app directly in your own Bun, Node, browser, or edge runtime:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { App } from "@supabase/lite";
|
|
97
|
+
import { createConnection } from "@supabase/lite/sqlite";
|
|
98
|
+
|
|
99
|
+
const connection = await createConnection({ url: "file:./data.db" });
|
|
100
|
+
const app = new App({ connection, auth: { enabled: true } });
|
|
101
|
+
|
|
102
|
+
const schema = await Bun.file("./schema.sql").text();
|
|
103
|
+
await app.connection.createMigrator(schema).migrate();
|
|
104
|
+
|
|
105
|
+
export default app; // app.fetch handles requests
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This is the path for custom server frameworks, Cloudflare Workers/Durable Objects, or any setup where you need to control the boot sequence yourself rather than delegating to the CLI or the Vite plugin. See [Embedded / programmatic](/integrations/embedded) for supported runtimes and drivers.
|
|
109
|
+
|
|
110
|
+
## Choosing
|
|
111
|
+
|
|
112
|
+
- Building a Vite app? Use the [Vite plugin](/integrations/vite). Stop here.
|
|
113
|
+
- Building anything else, and want schema changes to apply automatically while you iterate? Use `lite dev`.
|
|
114
|
+
- Deploying, running in CI, or want explicit control over migrations? Use `lite start`.
|
|
115
|
+
- Building your own server, or targeting a runtime the CLI doesn't drive directly (Workers, Durable Objects)? Use the [embedded API](/integrations/embedded).
|
|
116
|
+
|
|
117
|
+
Whichever mode you pick, run one per project. Two backends over the same SQLite file (two CLI processes, or a process plus the Vite plugin) race migrations and schema watchers against one database, even though they don't share a port.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Storage adapters"
|
|
3
|
+
description: "Pluggable storage backends (filesystem, S3-compatible) and transformation adapters (Noop, Sharp, Cloudflare) for Supabase Lite Storage."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
Supabase Lite's Storage API separates *where bytes live* (storage adapters) from *how images get resized* (transformation adapters). Both are supabase-js-invisible: the same `supabase.storage.from(...).upload()` call works no matter which adapter is wired up server-side. This adapter split is a Supabase Lite-specific implementation detail; there's no equivalent concept to configure in hosted Supabase.
|
|
9
|
+
|
|
10
|
+
<Aside type="note">
|
|
11
|
+
Storage is experimental. See [Storage overview](/storage/overview) for the `EXPERIMENTAL_STORAGE` flag and the config required before any adapter matters.
|
|
12
|
+
</Aside>
|
|
13
|
+
|
|
14
|
+
## Storage adapters
|
|
15
|
+
|
|
16
|
+
Where object bytes are physically stored.
|
|
17
|
+
|
|
18
|
+
| Adapter | Status | Notes |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Filesystem | Supported | Local disk. Default for `lite dev` / `lite start` under `.temp/storage`. |
|
|
21
|
+
| S3 / S3-compatible | Supported | MinIO, AWS S3, Cloudflare R2, via [`aws4fetch`](https://github.com/lquixada/aws4fetch), not the AWS SDK. |
|
|
22
|
+
| Cloudflare R2 | Supported | Uses the S3 adapter with R2's S3-compatible endpoint. |
|
|
23
|
+
|
|
24
|
+
### Filesystem
|
|
25
|
+
|
|
26
|
+
Set programmatically on the `App` instance:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { FilesystemStorageAdapter } from "@supabase/lite/storage/adapters/FilesystemStorageAdapter";
|
|
30
|
+
|
|
31
|
+
app._storageAdapter = new FilesystemStorageAdapter({
|
|
32
|
+
basePath: "./supabase/.temp/storage",
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This is what the `lite` CLI wires up automatically when `EXPERIMENTAL_STORAGE=1` and `storage.enabled` are set: object bytes land under `<config_dir>/.temp/storage/<bucket>/<key>`.
|
|
37
|
+
|
|
38
|
+
### S3-compatible
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { S3StorageAdapter } from "@supabase/lite/storage/adapters/S3StorageAdapter";
|
|
42
|
+
|
|
43
|
+
app._storageAdapter = new S3StorageAdapter({
|
|
44
|
+
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
|
|
45
|
+
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
|
|
46
|
+
endpoint: "https://<account>.r2.cloudflarestorage.com",
|
|
47
|
+
region: "auto",
|
|
48
|
+
bucket: "my-bucket", // optional: scope all operations to one S3 bucket
|
|
49
|
+
forcePathStyle: true, // required for MinIO and some S3-compatible providers
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`endpoint` and `region` point at whichever S3-compatible provider you use (AWS S3, MinIO, Cloudflare R2). `forcePathStyle` switches between virtual-hosted-style and path-style URLs; enable it for MinIO and most self-hosted S3-compatible servers.
|
|
54
|
+
|
|
55
|
+
For the S3 API surface this adapter targets on the wire, see [Supabase Storage S3 compatibility](https://supabase.com/docs/guides/storage/s3/compatibility). Note that's about Supabase's own S3-compatible *server* endpoint, which Supabase Lite does not yet implement server-side (see [Storage limitations](/storage/limitations)); this adapter is Supabase Lite acting as an S3 *client* to store bytes remotely.
|
|
56
|
+
|
|
57
|
+
## Transformation adapters
|
|
58
|
+
|
|
59
|
+
How (and whether) images get resized/reformatted on read.
|
|
60
|
+
|
|
61
|
+
| Adapter | Status | Notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| Noop | Supported | Passthrough: no transforms, returns the original bytes. Default. |
|
|
64
|
+
| Sharp | Supported | Resize + format conversion via [`sharp`](https://sharp.pixelplumbing.com/), in-process. Requires `sharp` as an optional dependency in your project. |
|
|
65
|
+
| Cloudflare | Supported | Delegates to [Cloudflare Image Resizing](https://developers.cloudflare.com/images/transform-images/transform-via-workers/) via `fetch` with `cf.image` options; no image-processing library, works in Workers. |
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { SharpTransformationAdapter } from "@supabase/lite/storage/transformations/SharpTransformationAdapter";
|
|
69
|
+
|
|
70
|
+
app._transformationAdapter = new SharpTransformationAdapter();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Pick Sharp for Node/Bun deployments where you want image transforms without an external image proxy, and Cloudflare's adapter when running on Workers, where Cloudflare's edge already handles resizing and a native image library isn't available. Leave the default Noop adapter if you don't need `?width=`/`?height=` transforms at all.
|
|
74
|
+
|
|
75
|
+
For the transform options themselves (`width`, `height`, `resize`, `format`, `quality`) and how they're requested from the client, see [Supabase image transformations](https://supabase.com/docs/guides/storage/serving/image-transformations).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Storage limitations"
|
|
3
|
+
description: "What's not yet implemented in Supabase Lite Storage: access control, RLS on objects, TUS uploads, webhooks, and the S3-compatible server protocol."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { Aside } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
Storage is [experimental](/storage/overview) and behind the `EXPERIMENTAL_STORAGE` flag. Everything below is a gap on top of that: even with the flag on and an adapter wired up, these features don't exist yet.
|
|
9
|
+
|
|
10
|
+
## Not yet implemented
|
|
11
|
+
|
|
12
|
+
| Feature | Notes |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Role-based access control | API keys resolve `service_role`/`anon`/`authenticated` for storage's route-level checks when configured (see [API keys](/auth/overview#api-keys)); still no per-object RLS. |
|
|
15
|
+
| RLS policies on storage tables | No per-user object access via row-level security on `storage.objects`. |
|
|
16
|
+
| `/status` health endpoint | Not registered. Upstream returns `200` with no auth required. |
|
|
17
|
+
| Bucket list query params | `GET /bucket` doesn't yet accept `?search=`, `?limit=`, `?offset=`. |
|
|
18
|
+
| S3-compatible protocol (server side) | No `PUT`/`GET`/`DELETE` under `/storage/v1/s3/*`. Supabase Lite can act as an S3 *client* via the [S3 storage adapter](/storage/adapters), but doesn't expose an S3-compatible server. |
|
|
19
|
+
| TUS resumable uploads | No `POST`/`PATCH`/`HEAD` on `/upload/resumable`. |
|
|
20
|
+
| Webhooks | No `ObjectCreated`/`ObjectRemoved` event delivery. |
|
|
21
|
+
|
|
22
|
+
<Aside type="caution">
|
|
23
|
+
Because there's no per-object RLS, anyone who can authenticate to `/storage/v1/*` (via a valid `anon`/`authenticated`/`service_role` key or session) has broad access to buckets they're routed to — there's no per-user object ownership check. Don't expose Supabase Lite Storage to untrusted clients.
|
|
24
|
+
</Aside>
|
|
25
|
+
|
|
26
|
+
## Workaround
|
|
27
|
+
|
|
28
|
+
For any of the above, run the storage-dependent parts of your app against hosted Supabase and keep the rest (Data API, Auth) on Supabase Lite. Mixed backends are a normal transitional setup, not something you need to migrate wholesale for.
|
|
29
|
+
|
|
30
|
+
For the target access-control model these gaps are working toward, see [Supabase Storage access control](https://supabase.com/docs/guides/storage). For what is implemented today, see [Storage overview](/storage/overview) and [Storage adapters](/storage/adapters).
|