supabase-js
This skill should be used when user asks to "use supabase-js", "query Supabase database", "supabase auth", "supabase storage", "supabase realtime", "supabase edge functions", or works with the @supabase/supabase-js JavaScript/TypeScript SDK.
Install
npx skills add https://github.com/fcakyon/claude-codex-settings/tree/main/plugins/supabase-skills/skills/supabase-js
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install fcakyon-claude-codex-settings@llmmart
git clone https://github.com/fcakyon/claude-codex-settings.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole fcakyon/claude-codex-settings collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Supabase JavaScript SDK Skill
Skill for building applications with the @supabase/supabase-js SDK. Covers Auth, Database (PostgREST), Storage, Realtime, and Edge Functions.
The SDK docs at https://supabase.com/docs/reference/javascript are the source of truth. The reference files alongside this skill contain source code and READMEs extracted from the monorepo for quick lookup.
Setup
npm install @supabase/supabase-js
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
For type-safe queries, generate types from your database schema:
supabase gen types typescript --project-id your-project-id > database.types.ts
import { createClient } from '@supabase/supabase-js'
import type { Database } from './database.types'
const supabase = createClient<Database>(SUPABASE_URL, SUPABASE_ANON_KEY)
Quick Decision Trees
"I need to query data"
Database query?
├─ Select rows → supabase.from('table').select('*')
├─ Filter rows → .select().eq('col', val) / .gt() / .lt() / .in() / .like()
├─ Join tables → .select('*, other_table(*)') or .select('*, other_table!fk(*)')
├─ Insert → supabase.from('table').insert({ col: val })
├─ Upsert → supabase.from('table').upsert({ id: 1, col: val })
├─ Update → supabase.from('table').update({ col: val }).eq('id', 1)
├─ Delete → supabase.from('table').delete().eq('id', 1)
├─ Call RPC function → supabase.rpc('function_name', { arg: val })
├─ Count rows → .select('*', { count: 'exact', head: true })
├─ Pagination → .range(0, 9) or .limit(10).offset(20)
└─ Order → .order('created_at', { ascending: false })
"I need authentication"
Auth?
├─ Email/password sign up → supabase.auth.signUp({ email, password })
├─ Email/password sign in → supabase.auth.signInWithPassword({ email, password })
├─ OAuth (Google, GitHub, etc.) → supabase.auth.signInWithOAuth({ provider: 'google' })
├─ Magic link → supabase.auth.signInWithOtp({ email })
├─ Phone OTP → supabase.auth.signInWithOtp({ phone })
├─ Sign out → supabase.auth.signOut()
├─ Get current user → supabase.auth.getUser()
├─ Get session → supabase.auth.getSession()
├─ Listen to auth changes → supabase.auth.onAuthStateChange((event, session) => {})
├─ Reset password → supabase.auth.resetPasswordForEmail(email)
├─ Update user → supabase.auth.updateUser({ data: { name: 'New' } })
└─ Admin operations → supabase.auth.admin.listUsers() / .deleteUser(id)
"I need file storage"
Storage?
├─ Upload file → supabase.storage.from('bucket').upload('path/file.png', file)
├─ Download file → supabase.storage.from('bucket').download('path/file.png')
├─ Get public URL → supabase.storage.from('bucket').getPublicUrl('path/file.png')
├─ Create signed URL → supabase.storage.from('bucket').createSignedUrl('path', 3600)
├─ List files → supabase.storage.from('bucket').list('folder')
├─ Move file → supabase.storage.from('bucket').move('old/path', 'new/path')
├─ Remove file → supabase.storage.from('bucket').remove(['path/file.png'])
├─ Create bucket → supabase.storage.createBucket('name', { public: false })
└─ List buckets → supabase.storage.listBuckets()
"I need realtime"
Realtime?
├─ Listen to DB changes → supabase.channel('name')
│ .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, handler)
│ .subscribe()
├─ Broadcast messages → channel.send({ type: 'broadcast', event: 'cursor', payload: { x, y } })
├─ Listen to broadcasts → .on('broadcast', { event: 'cursor' }, handler)
├─ Presence (who's online) → channel.track({ user_id, online_at })
│ .on('presence', { event: 'sync' }, () => channel.presenceState())
├─ Unsubscribe → supabase.removeChannel(channel)
└─ Unsubscribe all → supabase.removeAllChannels()
"I need edge functions"
Edge Functions?
├─ Invoke function → supabase.functions.invoke('function-name', { body: { key: 'val' } })
├─ With custom headers → .invoke('fn', { headers: { 'x-custom': 'val' }, body })
└─ Set region → .invoke('fn', { body, region: 'us-east-1' })
Common Patterns
Server-side with service role key
// Server-side only - bypasses RLS
const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, {
auth: { persistSession: false }
})
React/Next.js auth
import { createClient } from '@supabase/supabase-js'
import { useEffect, useState } from 'react'
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
function useUser() {
const [user, setUser] = useState(null)
useEffect(() => {
supabase.auth.getUser().then(({ data }) => setUser(data.user))
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_, session) => setUser(session?.user ?? null)
)
return () => subscription.unsubscribe()
}, [])
return user
}
Typed database queries
// Generated types give autocomplete for table names, column names, and return types
const { data, error } = await supabase
.from('profiles') // autocompleted table name
.select('id, username') // autocompleted columns
.eq('id', userId) // type-safe filter
.single() // returns single row or error
// data is typed as { id: string; username: string } | null
Package Index
| Package | Sub-client | Reference |
|---|---|---|
@supabase/supabase-js |
createClient() |
references/supabase-js/ |
@supabase/auth-js |
.auth |
references/auth-js/ |
@supabase/postgrest-js |
.from(), .rpc() |
references/postgrest-js/ |
@supabase/realtime-js |
.channel(), .realtime |
references/realtime-js/ |
@supabase/storage-js |
.storage |
references/storage-js/ |
@supabase/functions-js |
.functions |
references/functions-js/ |
Files (claude-codex-settings)
-
references
-
auth-js
-
README.md 6.5 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase Auth JS SDK</h1> <h3 align="center">An isomorphic JavaScript SDK for the <a href="https://github.com/supabase/auth">Supabase Auth</a> API.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/auth">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/auth-signup">Reference Docs</a> · <a href="https://supabase.github.io/supabase-js/auth-js/v2/spec.json">TypeDoc</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/auth-js) [](#license) [](https://pkg.pr.new/~/supabase/auth-js) </div> ## Requirements - **Node.js 22 or later** (Node.js 20 support dropped in v2.110.0) - For browser support, all modern browsers are supported > ⚠️ **Node.js 18 Deprecation Notice** > > Node.js 18 reached end-of-life on April 30, 2025. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/37217), support for Node.js 18 was dropped on October 31, 2025. > ⚠️ **Node.js 20 Deprecation Notice** > > Node.js 20 reached end-of-life on April 30, 2026. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/45715), support for Node.js 20 was dropped in v2.110.0. ## Quick start Install ```bash npm install --save @supabase/auth-js ``` Usage ```js import { AuthClient } from '@supabase/auth-js' const GOTRUE_URL = 'http://localhost:9999' const auth = new AuthClient({ url: GOTRUE_URL }) ``` - `signUp()`: https://supabase.com/docs/reference/javascript/auth-signup - `signIn()`: https://supabase.com/docs/reference/javascript/auth-signin - `signOut()`: https://supabase.com/docs/reference/javascript/auth-signout ### Custom `fetch` implementation `auth-js` uses the runtime's global `fetch` to make HTTP requests, but an alternative `fetch` implementation can be provided as an option. This is useful in environments where the global `fetch` is unavailable or where you want to customize request behavior: ```js import { AuthClient } from '@supabase/auth-js' const AUTH_URL = 'http://localhost:9999' const auth = new AuthClient({ url: AUTH_URL, fetch: fetch }) ``` ## Development This package is part of the [Supabase JavaScript monorepo](https://github.com/supabase/supabase-js). To work on this package: ### Building ```bash # Complete build (from monorepo root) pnpm nx build auth-js # Build with watch mode for development pnpm nx build auth-js --watch # Individual build targets pnpm nx build:main auth-js # CommonJS build (dist/main/) pnpm nx build:module auth-js # ES Modules build (dist/module/) # Other useful commands pnpm nx lint auth-js # Run ESLint pnpm nx typecheck auth-js # TypeScript type checking pnpm nx docs auth-js # Generate documentation ``` #### Build Outputs - **CommonJS (`dist/main/`)** - For Node.js environments - **ES Modules (`dist/module/`)** - For modern bundlers (Webpack, Vite, Rollup) - **TypeScript definitions (`dist/module/index.d.ts`)** - Type definitions for TypeScript projects ### Testing The auth-js package has two test suites: 1. **CLI Tests** - Main test suite using Supabase CLI (331 tests) 2. **Docker Tests** - Edge case tests requiring specific GoTrue configurations (11 tests) #### Prerequisites - **Supabase CLI** - Required for main test suite ([installation guide](https://supabase.com/docs/guides/cli)) - **Docker** - Required for edge case tests #### Running Tests ```bash # Run main test suite with Supabase CLI (recommended) pnpm nx test:auth auth-js # Run Docker-only edge case tests pnpm nx test:docker auth-js # Run both test suites pnpm nx test:auth auth-js && pnpm nx test:docker auth-js ``` #### Main Test Suite (Supabase CLI) The `test:auth` command automatically: 1. Stops any existing Supabase instance 2. Starts a local Supabase instance via CLI 3. Runs the test suite (excludes `docker-tests/` folder) 4. Cleans up after tests complete ```bash # Individual commands for manual control pnpm nx test:infra auth-js # Start Supabase CLI pnpm nx test:suite auth-js # Run tests only pnpm nx test:clean-post auth-js # Stop Supabase CLI ``` #### Docker Tests (Edge Cases) The `test:docker` target runs tests that require specific GoTrue configurations not possible with a single Supabase CLI instance: - **Signup disabled** - Tests for disabled signup functionality - **Asymmetric JWT (RS256)** - Tests for RS256 JWT verification - **Phone OTP / SMS** - Tests requiring Twilio SMS provider - **Anonymous sign-in disabled** - Tests for disabled anonymous auth These tests are located in `test/docker-tests/` and use the Docker Compose setup in `infra/docker-compose.yml`. ```bash # Individual commands for manual control pnpm nx test:docker:infra auth-js # Start Docker containers pnpm nx test:docker:suite auth-js # Run Docker tests only pnpm nx test:docker:clean-post auth-js # Stop Docker containers ``` #### Development Testing For actively developing and debugging tests: ```bash # Start Supabase CLI once pnpm nx test:infra auth-js # Run tests multiple times (faster since instance stays up) pnpm nx test:suite auth-js # Clean up when done pnpm nx test:clean-post auth-js ``` #### Test Infrastructure | Suite | Infrastructure | Configuration | | ------------ | -------------- | --------------------------- | | CLI Tests | Supabase CLI | `test/supabase/config.toml` | | Docker Tests | Docker Compose | `infra/docker-compose.yml` | ### Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes.
-
-
functions-js
-
README.md 4.8 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase Functions JS SDK</h1> <h3 align="center">JavaScript SDK to interact with Supabase Edge Functions.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/functions">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/functions-invoke">Reference Docs</a> · <a href="https://supabase.github.io/supabase-js/functions-js/v2/spec.json">TypeDoc</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/functions-js) [](#license) [](https://pkg.pr.new/~/supabase/functions-js) </div> ## Requirements - **Node.js 22 or later** (Node.js 20 support dropped in v2.110.0) - For browser support, all modern browsers are supported > ⚠️ **Node.js 18 Deprecation Notice** > > Node.js 18 reached end-of-life on April 30, 2025. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/37217), support for Node.js 18 was dropped on October 31, 2025. > ⚠️ **Node.js 20 Deprecation Notice** > > Node.js 20 reached end-of-life on April 30, 2026. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/45715), support for Node.js 20 was dropped in v2.110.0. ## Quick Start ### Installation ```bash npm install @supabase/functions-js ``` ### Usage ```js import { FunctionsClient } from '@supabase/functions-js' const functionsUrl = 'https://<project_ref>.supabase.co/functions/v1' const publishableKey = '<publishable_key>' const functions = new FunctionsClient(functionsUrl, { headers: { Authorization: `Bearer ${publishableKey}`, }, }) // Invoke a function const { data, error } = await functions.invoke('hello-world', { body: { name: 'Functions' }, }) ``` ## Development This package is part of the [Supabase JavaScript monorepo](https://github.com/supabase/supabase-js). To work on this package: ### Building ```bash # Complete build (from monorepo root) pnpm nx build functions-js # Build with watch mode for development pnpm nx build functions-js --watch # Individual build targets pnpm nx build:main functions-js # CommonJS build (dist/main/) pnpm nx build:module functions-js # ES Modules build (dist/module/) # Other useful commands pnpm nx clean functions-js # Clean build artifacts pnpm nx typecheck functions-js # TypeScript type checking pnpm nx docs functions-js # Generate documentation ``` #### Build Outputs - **CommonJS (`dist/main/`)** - For Node.js environments - **ES Modules (`dist/module/`)** - For modern bundlers (Webpack, Vite, Rollup) - **TypeScript definitions (`dist/module/index.d.ts`)** - Type definitions for TypeScript projects ### Testing **Docker Required** for relay tests. The functions-js tests use testcontainers to spin up a Deno relay server for testing Edge Function invocations. ```bash # Run all tests (from monorepo root) pnpm nx test functions-js # Run tests with coverage report pnpm nx test functions-js --coverage # Run tests in watch mode during development pnpm nx test functions-js --watch # CI test command (runs with coverage) pnpm nx test:ci functions-js ``` #### Test Requirements - **Node.js 22+** - Required for testcontainers - **Docker** - Must be installed and running for relay tests - No Supabase instance needed - Tests use mocked services and testcontainers #### What Gets Tested - **Function invocation** - Testing the `invoke()` method with various options - **Relay functionality** - Using a containerized Deno relay to test real Edge Function scenarios - **Error handling** - Ensuring proper error responses and retries - **Request/response models** - Validating headers, body, and response formats ### Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes.
-
-
postgrest-js
-
README.md 6.9 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase PostgREST JS SDK</h1> <h3 align="center">Isomorphic JavaScript SDK for <a href="https://postgrest.org">PostgREST</a> with an ORM-like interface.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/database">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/select">Reference Docs</a> · <a href="https://supabase.github.io/supabase-js/postgrest-js/v2/spec.json">TypeDoc</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/postgrest-js) [](#license) [](https://pkg.pr.new/~/supabase/postgrest-js) </div> ### Quick start Install ```bash npm install @supabase/postgrest-js ``` Usage ```js import { PostgrestClient } from '@supabase/postgrest-js' const REST_URL = 'http://localhost:3000' const postgrest = new PostgrestClient(REST_URL) ``` - [select()](https://supabase.com/docs/reference/javascript/select) - [insert()](https://supabase.com/docs/reference/javascript/insert) - [update()](https://supabase.com/docs/reference/javascript/update) - [delete()](https://supabase.com/docs/reference/javascript/delete) #### Custom `fetch` implementation `postgrest-js` uses the runtime's global `fetch` to make HTTP requests, but an alternative `fetch` implementation can be provided as an option. This is useful in environments where the global `fetch` is unavailable or where you want to customize request behavior: ```js import { PostgrestClient } from '@supabase/postgrest-js' const REST_URL = 'http://localhost:3000' const postgrest = new PostgrestClient(REST_URL, { fetch: (...args) => fetch(...args), }) ``` ## Development This package is part of the [Supabase JavaScript monorepo](https://github.com/supabase/supabase-js). To work on this package: ### Building ```bash # Build (from monorepo root) pnpm nx build postgrest-js # Build with watch mode for development pnpm nx build:watch postgrest-js # TypeScript type checking pnpm nx type-check postgrest-js # Generate documentation pnpm nx docs postgrest-js ``` ### Testing **Supabase CLI Required!** The `postgrest-js` tests use the [Supabase CLI](https://supabase.com/docs/guides/local-development/cli/getting-started) to run a local PostgreSQL database and PostgREST server. #### Quick Start ```bash # Run all tests (from monorepo root) pnpm nx test:ci:postgrest postgrest-js ``` This single command automatically: 1. Stops any existing Supabase CLI containers 2. Starts PostgreSQL database and PostgREST server via Supabase CLI 3. Resets and seeds the database 4. Runs all Jest unit tests with coverage 5. Cleans up containers #### Individual Test Commands ```bash # Run Jest tests with coverage (requires infrastructure running) pnpm nx test:run postgrest-js # Run type tests with tstyche pnpm nx test:types postgrest-js # Run smoke tests (CommonJS and ESM imports) pnpm nx test:smoke postgrest-js # Format code pnpm nx format postgrest-js # Check formatting pnpm nx format:check postgrest-js ``` #### Test Infrastructure The tests use Supabase CLI to spin up: - **PostgreSQL** - Database with test schema and seed data (port 54322) - **PostgREST** - REST API server that the client connects to (port 54321) ```bash # Manually manage test infrastructure (from monorepo root) pnpm nx test:infra postgrest-js # Start containers pnpm nx test:clean-pre postgrest-js # Stop and remove containers ``` Or directly via Supabase CLI: ```bash cd packages/core/postgrest-js npx supabase --workdir ./test start # Start all services npx supabase --workdir ./test db reset # Reset and seed database npx supabase --workdir ./test stop # Stop all services ``` #### Regenerating TypeScript Types When the database schema changes, regenerate TypeScript types from the actual database: ```bash # From the monorepo root pnpm run codegen:postgrest ``` This command automatically: 1. Cleans up any existing Supabase containers 2. Starts Supabase (PostgreSQL, PostgREST, and all services) 3. Generates TypeScript types from the database schema 4. Post-processes the generated types (updates JSON type definitions) 5. Formats the generated file with Prettier 6. Cleans up Supabase containers The generated types are written to `test/types.generated.ts`. #### Test Types Explained - **Unit Tests** - Jest tests covering all client functionality (`pnpm nx test:run postgrest-js`) - **Type Tests** - Validates TypeScript types using tstyche (`pnpm nx test:types postgrest-js`) - **Smoke Tests** - Basic import/require tests for CommonJS and ESM (`pnpm nx test:smoke postgrest-js`) #### Prerequisites - **Supabase CLI** must be installed ([instructions](https://supabase.com/docs/guides/local-development/cli/getting-started)) or can be used through `npx` (`npx supabase`) - **Docker** must be installed and running (Supabase CLI uses Docker under the hood) - **Port 54321** - PostgREST API - **Port 54322** - PostgreSQL database - **Port 54323** - Supabase Studio (used for type generation) #### PostgREST v12 Backward Compatibility Tests We maintain backward compatibility tests for PostgREST v12 (the current Supabase CLI uses v14+). These tests ensure the SDK works correctly for users still running older PostgREST versions. ```bash # Run v12 compatibility tests (requires Docker) pnpm nx test:ci:v12 postgrest-js ``` This command: 1. Starts PostgREST v12 + PostgreSQL in Docker (ports 3012/5433) 2. Runs runtime tests that verify v12-specific behavior 3. Cleans up containers **Type-only tests** for v12 compatibility also run as part of the regular type tests: ```bash pnpm nx test:types postgrest-js # Includes v12-compat.test-d.ts ``` **Note:** These v12 tests will be removed when v3 ships (sometime in 2026). ### Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes. ## License This repo is licensed under MIT License.
-
-
realtime-js
-
README.md 14.8 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase Realtime JS SDK</h1> <h3 align="center">Send ephemeral messages with <b>Broadcast</b>, track and synchronize state with <b>Presence</b>, and listen to database changes with <b>Postgres Change Data Capture (CDC)</b>.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/realtime">Guides</a> · <a href="https://supabase.com/docs/reference/javascript">Reference Docs</a> · <a href="https://multiplayer.dev">Multiplayer Demo</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/realtime-js) [](#license) [](https://pkg.pr.new/~/supabase/realtime-js) </div> # Overview This SDK enables you to use the following Supabase Realtime's features: - **Broadcast**: send ephemeral messages from client to clients with minimal latency. Use cases include sharing cursor positions between users. - **Presence**: track and synchronize shared state across clients with the help of CRDTs. Use cases include tracking which users are currently viewing a specific webpage. - **Postgres Change Data Capture (CDC)**: listen for changes in your PostgreSQL database and send them to clients. # Usage ## Installing the Package ```bash npm install @supabase/realtime-js ``` ## Creating a Channel ```js import { RealtimeClient } from '@supabase/realtime-js' const client = new RealtimeClient(REALTIME_URL, { params: { apikey: API_KEY, }, }) const channel = client.channel('test-channel', {}) channel.subscribe((status, err) => { if (status === 'SUBSCRIBED') { console.log('Connected!') } if (status === 'CHANNEL_ERROR') { console.log(`There was an error subscribing to channel: ${err.message}`) } if (status === 'TIMED_OUT') { console.log('Realtime server did not respond in time.') } if (status === 'CLOSED') { console.log('Realtime channel was unexpectedly closed.') } }) ``` ### Notes: - `REALTIME_URL` is `'ws://localhost:4000/socket'` when developing locally and `'wss://<project_ref>.supabase.co/realtime/v1'` when connecting to your Supabase project. - `API_KEY` is a JWT whose claims must contain `exp` and `role` (existing database role). - Channel name can be any `string`. - Setting `private` to `true` means that the client will use RLS to determine if the user can connect or not to a given channel. ## Broadcast Your client can send and receive messages based on the `event`. ```js // Setup... const channel = client.channel('broadcast-test', { broadcast: { ack: false, self: false } }) channel.on('broadcast', { event: 'some-event' }, (payload) => console.log(payload)) channel.subscribe(async (status) => { if (status === 'SUBSCRIBED') { // Send message to other clients listening to 'broadcast-test' channel await channel.send({ type: 'broadcast', event: 'some-event', payload: { hello: 'world' }, }) } }) ``` ### Notes: - Setting `ack` to `true` means that the `channel.send` promise will resolve once server replies with acknowledgment that it received the broadcast message request. - Setting `self` to `true` means that the client will receive the broadcast message it sent out. ### Broadcast Replay Broadcast Replay enables **private** channels to access messages that were sent earlier. Only messages published via [Broadcast From the Database](https://supabase.com/docs/guides/realtime/broadcast#trigger-broadcast-messages-from-your-database) are available for replay. You can configure replay with the following options: - **`since`** (Required): The epoch timestamp in milliseconds, specifying the earliest point from which messages should be retrieved. - **`limit`** (Optional): The number of messages to return. This must be a positive integer, with a maximum value of 25. Example: ```typescript const twelveHours = 12 * 60 * 60 * 1000 const twelveHoursAgo = Date.now() - twelveHours const config = { private: true, broadcast: { replay: { since: twelveHoursAgo, limit: 10 } } } supabase .channel('main:room', { config }) .on('broadcast', { event: 'my_event' }, (payload) => { if (payload?.meta?.replayed) { console.log('This message was sent earlier:', payload) } else { console.log('This is a new message', payload) } // ... }) .subscribe() ``` ## Presence Your client can track and sync state that's stored in the channel. ```js // Setup... const channel = client.channel('presence-test', { config: { presence: { key: '', }, }, }) channel.on('presence', { event: 'sync' }, () => { console.log('Online users: ', channel.presenceState()) }) channel.on('presence', { event: 'join' }, ({ newPresences }) => { console.log('New users have joined: ', newPresences) }) channel.on('presence', { event: 'leave' }, ({ leftPresences }) => { console.log('Users have left: ', leftPresences) }) channel.subscribe(async (status) => { if (status === 'SUBSCRIBED') { const status = await channel.track({ user_id: 1 }) console.log(status) } }) ``` > `config.presence.enabled` (set automatically if you add an `.on('presence', ...)` listener) > controls whether _this_ client receives presence state and updates from other clients — > without it, `presenceState()` stays empty for you. It does not affect whether other clients > see you: calling `track()` always makes you visible to subscribers that do have presence > enabled. On RLS-protected channels, receiving presence updates additionally requires the > `presence.read` policy to authorize this client. ## Postgres CDC Receive database changes on the client. ```js // Setup... const channel = client.channel('db-changes') channel.on('postgres_changes', { event: '*', schema: 'public' }, (payload) => { console.log('All changes in public schema: ', payload) }) channel.on( 'postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, (payload) => { console.log('All inserts in messages table: ', payload) } ) channel.on( 'postgres_changes', { event: 'UPDATE', schema: 'public', table: 'users', filter: 'username=eq.Realtime' }, (payload) => { console.log('All updates on users table when username is Realtime: ', payload) } ) channel.subscribe(async (status) => { if (status === 'SUBSCRIBED') { console.log('Ready to receive database changes!') } }) ``` ### Filters The `filter` option accepts **either** a raw string **or** a `postgresChangesFilter()` builder — both produce the exact same wire format, so you can mix and match and existing string filters keep working unchanged: ```js // Raw string — always supported, fully backward compatible { event: 'UPDATE', schema: 'public', table: 'users', filter: 'id=eq.1' } // Builder — type-checked, ergonomic; the SDK serializes it for you { event: 'UPDATE', schema: 'public', table: 'users', filter: postgresChangesFilter().eq('id', 1) } ``` A filter is a `column=operator.value` expression evaluated server-side. The following operators are supported: | Operator | String form | Builder | Meaning | | --------------------- | ---------------------------- | -------------------------------------- | --------------------------------- | | `eq` | `id=eq.1` | `.eq('id', 1)` | equal | | `neq` | `id=neq.1` | `.neq('id', 1)` | not equal | | `lt` `lte` `gt` `gte` | `age=gte.18` | `.gte('age', 18)` | comparison | | `in` | `status=in.(active,pending)` | `.in('status', ['active', 'pending'])` | in list | | `like` `ilike` | `title=like.%foo%` | `.like('title', '%foo%')` | pattern match (case in/sensitive) | | `is` | `deleted_at=is.null` | `.is('deleted_at', null)` | `IS null/true/false/unknown` | | `match` `imatch` | `title=match.^foo` | `.match('title', '^foo')` | POSIX regex match (`~` / `~*`) | | `isdistinct` | `value=isdistinct.1` | `.isDistinct('value', 1)` | NULL-safe inequality | **Negation** — prefix any operator with `not.` (string) or use `.not(column, operator, value)` (builder): ```js // String { event: '*', schema: 'public', table: 'posts', filter: 'status=not.in.(draft,archived)' } // Builder { event: '*', schema: 'public', table: 'posts', filter: postgresChangesFilter().not('status', 'in', ['draft', 'archived']), } ``` **AND composition** — multiple conditions are combined with commas and applied as an `AND`. With the builder you just chain calls: ```js // String { event: 'UPDATE', schema: 'public', table: 'orders', filter: 'amount=gt.100,status=in.(open,pending)' } // Builder — equivalent, chained { event: 'UPDATE', schema: 'public', table: 'orders', filter: postgresChangesFilter().gt('amount', 100).in('status', ['open', 'pending']), } ``` #### Building filters with `postgresChangesFilter()` The builder (modeled on the `postgrest-js` filter methods) is the recommended, type-checked way to compose filters — but it is entirely optional; raw strings remain fully supported. ```js import { postgresChangesFilter } from '@supabase/realtime-js' channel.on( 'postgres_changes', { event: 'UPDATE', schema: 'public', table: 'orders', // → 'amount=gt.100,status=not.in.(draft,archived)' filter: postgresChangesFilter().gt('amount', 100).not('status', 'in', ['draft', 'archived']), }, (payload) => console.log(payload) ) ``` The builder exposes `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `like`, `ilike`, `match`, `imatch`, `is`, `isDistinct` and `not`. Call `.build()` if you need the raw string yourself (e.g. to log it or store it). **Values are sent verbatim** — the server has no quoting/escaping, so spaces and quotes are preserved as-is. The server separates conditions by commas outside parentheses, so a literal comma in a scalar value can't be expressed (commas inside `in.(…)` are fine); the builder throws on such values rather than silently producing a broken filter. > **Note for PostgREST users:** Realtime evaluates filters server-side over a > single table's WAL — there is no resource embedding (`!inner`, embedded > filters) and no `or()` grouping. Use `%` (not `*`) for `like`/`ilike` > wildcards, since filters travel in the WebSocket payload rather than a URL. ### Selecting columns Use `select` to receive only a subset of columns instead of the full row. This reduces payload size (helpful for large `bytea`/`jsonb` columns). The selected columns must be selectable by the subscribing role: ```js channel.on( 'postgres_changes', { event: '*', schema: 'public', table: 'users', select: ['id', 'first_name'] }, (payload) => { // payload.new only contains { id, first_name } console.log(payload) } ) ``` ## Get All Channels You can see all the channels that your client has instantiatied. ```js // Setup... client.getChannels() ``` ## Cleanup It is highly recommended that you clean up your channels after you're done with them. - Remove a single channel ```js // Setup... const channel = client.channel('some-channel-to-remove') channel.unsubscribe() client.removeChannel(channel) ``` - Remove all channels and close the connection ```js // Setup... client.removeAllChannels() client.disconnect() ``` ## Development This package is part of the [Supabase JavaScript monorepo](https://github.com/supabase/supabase-js). To work on this package: ### Building ```bash # Complete build (from monorepo root) pnpm nx build realtime-js # Build with watch mode for development pnpm nx build realtime-js --watch # Individual build targets pnpm nx build:main realtime-js # CommonJS build (dist/main/) pnpm nx build:module realtime-js # ES Modules build (dist/module/) # Other useful commands pnpm nx clean realtime-js # Clean build artifacts pnpm nx lint realtime-js # Run ESLint pnpm nx typecheck realtime-js # TypeScript type checking ``` #### Build Outputs - **CommonJS (`dist/main/`)** - For Node.js environments - **ES Modules (`dist/module/`)** - For modern bundlers (Webpack, Vite, Rollup) - **TypeScript definitions (`dist/module/index.d.ts`)** - Type definitions for TypeScript projects Note: Unlike some other packages, realtime-js doesn't include a UMD build since it's primarily used in Node.js or bundled applications. #### Validating Package Exports ```bash # Check if package exports are correctly configured pnpm nx check-exports realtime-js ``` This command uses ["Are the types wrong?"](https://github.com/arethetypeswrong/arethetypeswrong.github.io) to verify that the package exports work correctly in different environments. Run this before publishing to ensure your package can be imported correctly by all consumers. ### Testing **No Docker or Supabase instance required!** The realtime-js tests use mocked WebSocket connections, so they're completely self-contained. ```bash # Run unit tests (from monorepo root) pnpm nx test realtime-js # Run tests with coverage report pnpm nx test:coverage realtime-js # Run tests in watch mode during development pnpm nx test:watch realtime-js ``` #### Test Scripts Explained - **test** - Runs all unit tests once using Vitest - **test:coverage** - Runs tests and generates coverage report with terminal output - **test:watch** - Runs tests in interactive watch mode for development The tests mock WebSocket connections using `mock-socket`, so you can run them anytime without any external dependencies. ### Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes. ## Credits This repo draws heavily from [phoenix-js](https://github.com/phoenixframework/phoenix/tree/master/assets/js/phoenix). ## License MIT.
-
-
storage-js
-
README.md 35.7 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase Storage JS SDK</h1> <h3 align="center">JavaScript SDK to interact with Supabase Storage, including file storage and vector embeddings.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/storage">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/storage-createbucket">Reference Docs</a> · <a href="https://supabase.github.io/supabase-js/storage-js/v2/spec.json">TypeDoc</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/storage-js) [](#license) [](https://pkg.pr.new/~/supabase/storage-js) </div> ## Requirements - **Node.js 22 or later** (Node.js 20 support dropped in v2.110.0) - For browser support, all modern browsers are supported > ⚠️ **Node.js 18 Deprecation Notice** > > Node.js 18 reached end-of-life on April 30, 2025. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/37217), support for Node.js 18 was dropped on October 31, 2025. > ⚠️ **Node.js 20 Deprecation Notice** > > Node.js 20 reached end-of-life on April 30, 2026. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/45715), support for Node.js 20 was dropped in v2.110.0. ## Features - **File Storage**: Upload, download, list, move, and delete files - **Access Control**: Public and private buckets with fine-grained permissions - **Signed URLs**: Generate time-limited URLs for secure file access - **Image Transformations**: On-the-fly image resizing and optimization - **Vector Embeddings**: Store and query high-dimensional embeddings with similarity search - **Analytics Buckets**: Iceberg table-based buckets optimized for analytical queries and data processing - **Lifecycle**: Expire previous versions of objects after a number of days ## Quick Start Guide ### Installing the module ```bash npm install @supabase/storage-js ``` ### Connecting to the storage backend There are two ways to use the Storage SDK: #### Option 1: Via Supabase Client (Recommended) If you're already using `@supabase/supabase-js`, access storage through the client: ```js import { createClient } from '@supabase/supabase-js' // Use publishable key for frontend applications const supabase = createClient('https://<project_ref>.supabase.co', '<your-publishable-key>') // Access storage const storage = supabase.storage // Access different bucket types const regularBucket = storage.from('my-bucket') const vectorBucket = storage.vectors.from('embeddings-bucket') const analyticsBucket = storage.analytics // Analytics API ``` #### Option 2: Standalone StorageClient For backend applications or when you need to bypass Row Level Security: ```js import { StorageClient } from '@supabase/storage-js' const STORAGE_URL = 'https://<project_ref>.supabase.co/storage/v1' const SERVICE_KEY = '<your-secret-key>' // Use secret key for backend operations const storageClient = new StorageClient(STORAGE_URL, { apikey: SERVICE_KEY, Authorization: `Bearer ${SERVICE_KEY}`, }) // Access different bucket types const regularBucket = storageClient.from('my-bucket') const vectorBucket = storageClient.vectors.from('embeddings-bucket') const analyticsBucket = storageClient.analytics // Analytics API ``` > **When to use each approach:** > > - Use `supabase.storage` when working with other Supabase features (auth, database, etc.) in frontend applications > - Use `new StorageClient()` for backend applications, Edge Functions, or when you need to bypass RLS policies > **Note:** Refer to the [Storage Access Control guide](https://supabase.com/docs/guides/storage/access-control) for detailed information on creating RLS policies. ### Understanding Bucket Types Supabase Storage supports three types of buckets, each optimized for different use cases: #### 1. Regular Storage Buckets (File Storage) Standard buckets for storing files, images, videos, and other assets. ```js // Create regular storage bucket const { data, error } = await storageClient.createBucket('my-files', { public: false, }) // Upload files await storageClient.from('my-files').upload('avatar.png', file) ``` **Use cases:** User uploads, media assets, documents, backups #### 2. Vector Buckets (Embeddings Storage) Specialized buckets for storing and querying high-dimensional vector embeddings. ```js // Create vector bucket await storageClient.vectors.createBucket('embeddings-prod') // Create index and insert vectors const bucket = storageClient.vectors.from('embeddings-prod') await bucket.createIndex({ indexName: 'documents', dimension: 1536, distanceMetric: 'cosine', }) ``` **Use cases:** Semantic search, AI-powered recommendations, similarity matching **[See full Vector Embeddings documentation below](#vector-embeddings)** #### 3. Analytics Buckets Specialized buckets using Apache Iceberg table format, optimized for analytical queries and large-scale data processing. ```js // Create analytics bucket await storageClient.analytics.createBucket('analytics-data') // List analytics buckets const { data, error } = await storageClient.analytics.listBuckets() // Delete analytics bucket await storageClient.analytics.deleteBucket('analytics-data') ``` **Use cases:** Time-series data, analytical queries, data lakes, large-scale data processing, business intelligence **[See full Analytics Buckets documentation below](#analytics-buckets)** --- ### Handling resources #### Handling Storage Buckets - Create a new Storage bucket: ```js const { data, error } = await storageClient.createBucket( 'test_bucket', // Bucket name (must be unique) { public: false } // Bucket options ) ``` - Retrieve the details of an existing Storage bucket: ```js const { data, error } = await storageClient.getBucket('test_bucket') ``` - Update a new Storage bucket: ```js const { data, error } = await storageClient.updateBucket( 'test_bucket', // Bucket name { public: false } // Bucket options ) ``` - Remove all objects inside a single bucket: ```js const { data, error } = await storageClient.emptyBucket('test_bucket') ``` - Delete an existing bucket (a bucket can't be deleted with existing objects inside it): ```js const { data, error } = await storageClient.deleteBucket('test_bucket') ``` - Retrieve the details of all Storage buckets within an existing project: ```js // List all buckets const { data, error } = await storageClient.listBuckets() // List buckets with options (pagination, sorting, search) const { data, error } = await storageClient.listBuckets({ limit: 10, offset: 0, sortColumn: 'created_at', sortOrder: 'desc', search: 'prod', }) ``` - Manage a bucket's lifecycle policy. Rules expire **previous versions** of objects after a number of days, so versioning needs to be enabled or the policy has nothing to act on. This is Standard buckets only, and the project must have lifecycle enabled. ```js // Replaces every existing rule const { data, error } = await storageClient.updateBucketLifecycle('test_bucket', { rules: [ { id: 'expire-old-versions', status: 'Enabled', filter: {}, noncurrentVersionExpiration: { noncurrentDays: 30 }, }, ], }) // Fails with NoSuchLifecycleConfiguration when the bucket has no policy const { data: config, error: configError } = await storageClient.getBucketLifecycle('test_bucket') await storageClient.deleteBucketLifecycle('test_bucket') ``` #### Handling Files - Upload a file to an existing bucket: ```js const fileBody = ... // load your file here const { data, error } = await storageClient.from('bucket').upload('path/to/file', fileBody) ``` > Note: > The path in `data.Key` is prefixed by the bucket ID and is not the value which should be passed to the `download` method in order to fetch the file. > To fetch the file via the `download` method, use `data.path` and `data.bucketId` as follows: > > ```javascript > const { data, error } = await storageClient.from('bucket').upload('/folder/file.txt', fileBody) > // check for errors > const { data2, error2 } = await storageClient.from(data.bucketId).download(data.path) > ``` > Note: The `upload` method also accepts a map of optional parameters. For a complete list see the [Supabase API reference](https://supabase.com/docs/reference/javascript/storage-from-upload). - Download a file from an exisiting bucket: ```js const { data, error } = await storageClient.from('bucket').download('path/to/file') ``` - List all the files within a bucket: ```js const { data, error } = await storageClient.from('bucket').list('folder') ``` > Note: The `list` method also accepts a map of optional parameters. For a complete list see the [Supabase API reference](https://supabase.com/docs/reference/javascript/storage-from-list). - Replace an existing file at the specified path with a new one: ```js const fileBody = ... // load your file here const { data, error } = await storageClient .from('bucket') .update('path/to/file', fileBody) ``` > Note: The `upload` method also accepts a map of optional parameters. For a complete list see the [Supabase API reference](https://supabase.com/docs/reference/javascript/storage-from-upload). - Move an existing file: ```js const { data, error } = await storageClient .from('bucket') .move('old/path/to/file', 'new/path/to/file') ``` - Delete files within the same bucket: ```js const { data, error } = await storageClient.from('bucket').remove(['path/to/file']) ``` - Create signed URL to download file without requiring permissions: ```js const expireIn = 60 const { data, error } = await storageClient .from('bucket') .createSignedUrl('path/to/file', expireIn) ``` - Retrieve URLs for assets in public buckets: ```js const { data, error } = await storageClient.from('public-bucket').getPublicUrl('path/to/file') ``` ## Analytics Buckets Supabase Storage provides specialized analytics buckets using Apache Iceberg table format, optimized for analytical workloads and large-scale data processing. These buckets are designed for data lake architectures, time-series data, and business intelligence applications. ### What are Analytics Buckets? Analytics buckets use the Apache Iceberg open table format, providing: - **ACID transactions** for data consistency - **Schema evolution** without data rewrites - **Time travel** to query historical data - **Efficient metadata management** for large datasets - **Optimized for analytical queries** rather than individual file operations ### When to Use Analytics Buckets **Use analytics buckets for:** - Time-series data (logs, metrics, events) - Data lake architectures - Business intelligence and reporting - Large-scale batch processing - Analytical workloads requiring ACID guarantees **Use regular storage buckets for:** - User file uploads (images, documents, videos) - Individual file management - Content delivery - Simple object storage needs ### Quick Start You can access analytics functionality through the `analytics` property on your storage client: #### Via Supabase Client ```typescript import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project.supabase.co', 'your-publishable-key') // Access analytics operations const analytics = supabase.storage.analytics // Create an analytics bucket const { data, error } = await analytics.createBucket('analytics-data') if (error) { console.error('Failed to create analytics bucket:', error.message) } else { console.log('Created bucket:', data.name) } ``` #### Via StorageClient ```typescript import { StorageClient } from '@supabase/storage-js' const storageClient = new StorageClient('https://your-project.supabase.co/storage/v1', { apikey: 'YOUR_API_KEY', Authorization: 'Bearer YOUR_TOKEN', }) // Access analytics operations const analytics = storageClient.analytics // Create an analytics bucket await analytics.createBucket('analytics-data') ``` ### API Reference #### Create Analytics Bucket Creates a new analytics bucket using Iceberg table format: ```typescript const { data, error } = await analytics.createBucket('my-analytics-bucket') if (error) { console.error('Error:', error.message) } else { console.log('Created bucket:', data) } ``` **Returns:** ```typescript { data: { id: string type: 'ANALYTICS' format: string created_at: string updated_at: string } | null error: StorageError | null } ``` #### List Analytics Buckets Retrieves all analytics buckets in your project with optional filtering and pagination: ```typescript const { data, error } = await analytics.listBuckets({ limit: 10, offset: 0, sortColumn: 'created_at', sortOrder: 'desc', search: 'prod', }) if (data) { console.log(`Found ${data.length} analytics buckets`) data.forEach((bucket) => { console.log(`- ${bucket.id} (created: ${bucket.created_at})`) }) } ``` **Parameters:** - `limit?: number` - Maximum number of buckets to return - `offset?: number` - Number of buckets to skip (for pagination) - `sortColumn?: 'id' | 'name' | 'created_at' | 'updated_at'` - Column to sort by - `sortOrder?: 'asc' | 'desc'` - Sort direction - `search?: string` - Search term to filter bucket names **Returns:** ```typescript { data: AnalyticBucket[] | null error: StorageError | null } ``` **Example with Pagination:** ```typescript // Fetch first page const firstPage = await analytics.listBuckets({ limit: 100, offset: 0, sortColumn: 'created_at', sortOrder: 'desc', }) // Fetch second page const secondPage = await analytics.listBuckets({ limit: 100, offset: 100, sortColumn: 'created_at', sortOrder: 'desc', }) ``` #### Delete Analytics Bucket Deletes an analytics bucket. The bucket must be empty before deletion. ```typescript const { data, error } = await analytics.deleteBucket('old-analytics-bucket') if (error) { console.error('Failed to delete:', error.message) } else { console.log('Bucket deleted:', data.message) } ``` **Returns:** ```typescript { data: { message: string } | null error: StorageError | null } ``` > **Note:** A bucket cannot be deleted if it contains data. You must empty the bucket first. #### Get Iceberg Catalog for Advanced Operations For advanced operations like creating tables, namespaces, and querying Iceberg metadata, use the `from()` method to get a configured [iceberg-js](https://github.com/supabase/iceberg-js) client: ```typescript // Get an Iceberg REST Catalog client for your analytics bucket const catalog = analytics.from('analytics-data') // Create a namespace await catalog.createNamespace({ namespace: ['default'] }, { properties: { owner: 'data-team' } }) // Create a table with schema await catalog.createTable( { namespace: ['default'] }, { name: 'events', schema: { type: 'struct', fields: [ { id: 1, name: 'id', type: 'long', required: true }, { id: 2, name: 'timestamp', type: 'timestamp', required: true }, { id: 3, name: 'user_id', type: 'string', required: false }, ], 'schema-id': 0, 'identifier-field-ids': [1], }, 'partition-spec': { 'spec-id': 0, fields: [], }, 'write-order': { 'order-id': 0, fields: [], }, properties: { 'write.format.default': 'parquet', }, } ) // List tables in namespace const tables = await catalog.listTables({ namespace: ['default'] }) console.log(tables) // [{ namespace: ['default'], name: 'events' }] // Load table metadata const table = await catalog.loadTable({ namespace: ['default'], name: 'events' }) // Update table properties await catalog.updateTable( { namespace: ['default'], name: 'events' }, { properties: { 'read.split.target-size': '134217728' } } ) // Drop table await catalog.dropTable({ namespace: ['default'], name: 'events' }) // Drop namespace await catalog.dropNamespace({ namespace: ['default'] }) ``` **Returns:** `IcebergRestCatalog` instance from [iceberg-js](https://github.com/supabase/iceberg-js) > **Note:** The `from()` method returns an Iceberg REST Catalog client that provides full access to the Apache Iceberg REST API. For complete documentation of available operations, see the [iceberg-js documentation](https://supabase.github.io/iceberg-js/). ### Error Handling Analytics buckets use the same error handling pattern as the rest of the Storage SDK: ```typescript const { data, error } = await analytics.createBucket('my-bucket') if (error) { console.error('Error:', error.message) console.error('Status:', error.status) console.error('Status Code:', error.statusCode) // Handle error appropriately } ``` #### Throwing Errors You can configure the client to throw errors instead of returning them: ```typescript const analytics = storageClient.analytics analytics.throwOnError() try { const { data } = await analytics.createBucket('my-bucket') // data is guaranteed to be present console.log('Success:', data) } catch (error) { if (error instanceof StorageApiError) { console.error('API Error:', error.statusCode, error.message) } } ``` ### TypeScript Types The library exports TypeScript types for analytics buckets: ```typescript import type { AnalyticBucket, BucketType, StorageError } from '@supabase/storage-js' // AnalyticBucket type interface AnalyticBucket { id: string type: 'ANALYTICS' format: string created_at: string updated_at: string } ``` ### Common Patterns #### Checking if a Bucket Exists ```typescript async function bucketExists(bucketName: string): Promise<boolean> { const { data, error } = await analytics.listBuckets({ search: bucketName, }) if (error) { console.error('Error checking bucket:', error.message) return false } return data?.some((bucket) => bucket.id === bucketName) ?? false } ``` #### Creating Bucket with Error Handling ```typescript async function ensureAnalyticsBucket(bucketName: string) { // Try to create the bucket const { data, error } = await analytics.createBucket(bucketName) if (error) { // Check if bucket already exists (conflict error) if (error.statusCode === '409') { console.log(`Bucket '${bucketName}' already exists`) return { success: true, created: false } } // Other error occurred console.error('Failed to create bucket:', error.message) return { success: false, error } } console.log(`Created new bucket: '${bucketName}'`) return { success: true, created: true, data } } ``` #### Listing All Buckets with Pagination ```typescript async function getAllAnalyticsBuckets() { const allBuckets: AnalyticBucket[] = [] let offset = 0 const limit = 100 while (true) { const { data, error } = await analytics.listBuckets({ limit, offset, sortColumn: 'created_at', sortOrder: 'desc', }) if (error) { console.error('Error fetching buckets:', error.message) break } if (!data || data.length === 0) { break } allBuckets.push(...data) // If we got fewer results than the limit, we've reached the end if (data.length < limit) { break } offset += limit } return allBuckets } ``` ## Vector Embeddings Supabase Storage provides built-in support for storing and querying high-dimensional vector embeddings, powered by S3 Vectors. This enables semantic search, similarity matching, and AI-powered applications without needing a separate vector database. > **Note:** Vector embeddings functionality is available in `@supabase/storage-js` v2.76 and later. ### Features - **Vector Buckets**: Organize vector indexes into logical containers - **Vector Indexes**: Define schemas with configurable dimensions and distance metrics - **Batch Operations**: Insert/update/delete up to 500 vectors per request - **Similarity Search**: Query for nearest neighbors using cosine, euclidean, or dot product distance - **Metadata Filtering**: Store and filter vectors by arbitrary JSON metadata - **Pagination**: Efficiently scan large vector datasets - **Parallel Scanning**: Distribute scans across multiple workers for high throughput - **Cross-platform**: Works in Node.js, browsers, and edge runtimes ### Quick Start You can access vector functionality in three ways, depending on your use case: #### Option 1: Via Supabase Client (Most Common) If you're using the full Supabase client: ```typescript import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project.supabase.co', 'your-publishable-key') // Access vector operations through storage const vectors = supabase.storage.vectors // Create a vector bucket await vectors.createBucket('embeddings-prod') // Create an index const bucket = vectors.from('embeddings-prod') await bucket.createIndex({ indexName: 'documents-openai', dataType: 'float32', dimension: 1536, distanceMetric: 'cosine', }) // Insert vectors const index = bucket.index('documents-openai') await index.putVectors({ vectors: [ { key: 'doc-1', data: { float32: [0.1, 0.2, 0.3 /* ...1536 dimensions */] }, metadata: { title: 'Introduction', category: 'docs' }, }, ], }) // Query similar vectors const { data, error } = await index.queryVectors({ queryVector: { float32: [0.15, 0.25, 0.35 /* ...1536 dimensions */] }, topK: 5, returnDistance: true, returnMetadata: true, }) if (data) { data.vectors.forEach((match) => { console.log(`${match.key}: distance=${match.distance}`) console.log('Metadata:', match.metadata) }) } ``` #### Option 2: Via StorageClient If you're using the standalone `StorageClient` for storage operations, access vectors through the `vectors` property: ```typescript import { StorageClient } from '@supabase/storage-js' const storageClient = new StorageClient('https://your-project.supabase.co/storage/v1', { apikey: 'YOUR_API_KEY', Authorization: 'Bearer YOUR_TOKEN', }) // Access vector operations const vectors = storageClient.vectors // Use the same API as shown in Option 1 await vectors.createBucket('embeddings-prod') const bucket = vectors.from('embeddings-prod') // ... rest of operations ``` #### Option 3: Standalone Vector Client For vector-only applications that don't need regular file storage operations: ```typescript import { StorageVectorsClient } from '@supabase/storage-js' // Initialize standalone vector client const vectorClient = new StorageVectorsClient('https://your-project.supabase.co/storage/v1', { headers: { Authorization: 'Bearer YOUR_TOKEN' }, }) // Use the same API as shown in Option 1 await vectorClient.createBucket('embeddings-prod') const bucket = vectorClient.from('embeddings-prod') // ... rest of operations ``` > **When to use each approach:** > > - **Option 1**: When using other Supabase features (auth, database, realtime) > - **Option 2**: When working with both file storage and vectors > - **Option 3**: For dedicated vector-only applications without file storage ### API Reference #### Client Initialization ```typescript const vectorClient = new StorageVectorsClient(url, options?) ``` **Options:** - `headers?: Record<string, string>` - Custom HTTP headers (e.g., Authorization) - `fetch?: Fetch` - Custom fetch implementation #### Vector Buckets Vector buckets are top-level containers for organizing vector indexes. ##### Create Bucket ```typescript const { data, error } = await vectorClient.createBucket('my-bucket') ``` ##### Get Bucket ```typescript const { data, error } = await vectorClient.getBucket('my-bucket') console.log('Created at:', new Date(data.vectorBucket.creationTime! * 1000)) ``` ##### List Buckets ```typescript const { data, error } = await vectorClient.listBuckets({ prefix: 'prod-', maxResults: 100, }) // Pagination if (data?.nextToken) { const next = await vectorClient.listBuckets({ nextToken: data.nextToken }) } ``` ##### Delete Bucket ```typescript // Bucket must be empty (all indexes deleted first) const { error } = await vectorClient.deleteBucket('my-bucket') ``` #### Vector Indexes Vector indexes define the schema for embeddings including dimension and distance metric. ##### Create Index ```typescript const bucket = vectorClient.from('my-bucket') await bucket.createIndex({ indexName: 'my-index', dataType: 'float32', dimension: 1536, distanceMetric: 'cosine', // 'cosine' | 'euclidean' | 'dotproduct' metadataConfiguration: { nonFilterableMetadataKeys: ['raw_text', 'internal_id'], }, }) ``` **Distance Metrics:** - `cosine` - Cosine similarity (normalized dot product) - `euclidean` - Euclidean distance (L2 norm) - `dotproduct` - Dot product similarity ##### Get Index ```typescript const { data, error } = await bucket.getIndex('my-index') console.log('Dimension:', data?.index.dimension) console.log('Distance metric:', data?.index.distanceMetric) ``` ##### List Indexes ```typescript const { data, error } = await bucket.listIndexes({ prefix: 'documents-', maxResults: 100, }) ``` ##### Delete Index ```typescript // Deletes index and all its vectors await bucket.deleteIndex('my-index') ``` #### Vector Operations ##### Insert/Update Vectors (Upsert) ```typescript const index = vectorClient.from('my-bucket').index('my-index') await index.putVectors({ vectors: [ { key: 'unique-id-1', data: { float32: [ /* 1536 numbers */ ], }, metadata: { title: 'Document Title', category: 'technical', page: 1, }, }, // ... up to 500 vectors per request ], }) ``` **Limitations:** - 1-500 vectors per request - Vectors must match index dimension - Keys must be unique within index ##### Get Vectors by Key ```typescript const { data, error } = await index.getVectors({ keys: ['doc-1', 'doc-2', 'doc-3'], returnData: true, // Include embeddings returnMetadata: true, // Include metadata }) data?.vectors.forEach((v) => { console.log(v.key, v.metadata) }) ``` ##### Query Similar Vectors (ANN Search) ```typescript const { data, error } = await index.queryVectors({ queryVector: { float32: [ /* 1536 numbers */ ], }, topK: 10, filter: { category: 'technical', published: true, }, returnDistance: true, returnMetadata: true, }) // Results ordered by similarity data?.vectors.forEach((match) => { console.log(`${match.key}: distance=${match.distance}`) }) ``` S3 vector buckets support deep queries with `topK` up to 10,000, returning at most 100 vectors per response. Pass the response's `nextToken` with the same query to retrieve the next page: ```typescript const query = { queryVector: { float32: embedding }, topK: 1000, returnDistance: true, } let nextToken: string | undefined do { const { data, error } = await index.queryVectors({ ...query, nextToken }) if (error) throw error for (const vector of data.vectors) { console.log(`${vector.key}: distance=${vector.distance}`) } nextToken = data.nextToken } while (nextToken) ``` The pgvector backend supports `topK` up to 100 and does not support `nextToken` pagination. **Filter Syntax:** The `filter` parameter accepts arbitrary JSON for metadata filtering. Non-filterable keys (configured at index creation) cannot be used in filters but can still be returned. ##### List/Scan Vectors ```typescript // Simple pagination let nextToken: string | undefined do { const { data } = await index.listVectors({ maxResults: 500, nextToken, returnMetadata: true, }) console.log('Batch:', data?.vectors.length) nextToken = data?.nextToken } while (nextToken) // Parallel scanning (4 workers) const workers = [0, 1, 2, 3].map(async (segmentIndex) => { const { data } = await index.listVectors({ segmentCount: 4, segmentIndex, returnMetadata: true, }) return data?.vectors || [] }) const results = await Promise.all(workers) const allVectors = results.flat() ``` **Limitations:** - `maxResults`: 1-1000 (default: 500) - `segmentCount`: 1-16 - Response may be limited by 1MB size ##### Delete Vectors ```typescript await index.deleteVectors({ keys: ['doc-1', 'doc-2', 'doc-3'], // ... up to 500 keys per request }) ``` ### Error Handling The library uses a consistent error handling pattern: ```typescript const { data, error } = await vectorClient.createBucket('my-bucket') if (error) { console.error('Error:', error.message) console.error('Status:', error.status) console.error('Code:', error.statusCode) } ``` #### Error Codes | Code | HTTP | Description | | ---------------------------- | ---- | ----------------------- | | `InternalError` | 500 | Internal server error | | `S3VectorConflictException` | 409 | Resource already exists | | `S3VectorNotFoundException` | 404 | Resource not found | | `S3VectorBucketNotEmpty` | 400 | Bucket contains indexes | | `S3VectorMaxBucketsExceeded` | 400 | Bucket quota exceeded | | `S3VectorMaxIndexesExceeded` | 400 | Index quota exceeded | #### Throwing Errors You can configure the client to throw errors instead: ```typescript const vectorClient = new StorageVectorsClient(url, options) vectorClient.throwOnError() try { const { data } = await vectorClient.createBucket('my-bucket') // data is guaranteed to be present } catch (error) { if (error instanceof StorageVectorsApiError) { console.error('API Error:', error.statusCode) } } ``` ### Advanced Usage #### Scoped Clients Create scoped clients for cleaner code: ```typescript // Bucket-scoped operations const bucket = vectorClient.from('embeddings-prod') await bucket.createIndex({ /* ... */ }) await bucket.listIndexes() // Index-scoped operations const index = bucket.index('documents-openai') await index.putVectors({ /* ... */ }) await index.queryVectors({ /* ... */ }) ``` #### Custom Fetch Provide a custom fetch implementation: ```typescript import { StorageVectorsClient } from '@supabase/storage-js' const vectorClient = new StorageVectorsClient(url, { fetch: customFetch, headers: { /* ... */ }, }) ``` #### Batch Processing Process large datasets in batches: ```typescript async function insertLargeDataset(vectors: VectorObject[]) { const batchSize = 500 for (let i = 0; i < vectors.length; i += batchSize) { const batch = vectors.slice(i, i + batchSize) await index.putVectors({ vectors: batch }) console.log(`Inserted ${i + batch.length}/${vectors.length}`) } } ``` #### Float32 Validation Ensure vectors are properly normalized to float32: ```typescript import { normalizeToFloat32 } from '@supabase/storage-js' const vector = normalizeToFloat32([0.1, 0.2, 0.3 /* ... */]) ``` ### Type Definitions The library exports comprehensive TypeScript types: ```typescript import type { VectorBucket, VectorIndex, VectorData, VectorObject, VectorMatch, VectorMetadata, DistanceMetric, ApiResponse, StorageVectorsError, } from '@supabase/storage-js' ``` ## Development This package is part of the [Supabase JavaScript monorepo](https://github.com/supabase/supabase-js). To work on this package: ### Building #### Build Scripts Overview ```bash # Build the package pnpm nx build storage-js # Watch mode for development pnpm nx build storage-js --watch # Generate documentation pnpm nx docs storage-js ``` ### Testing **Important:** The storage-js tests require a local Supabase stack running via the Supabase CLI. Docker must be running since the Supabase CLI uses it internally. #### Prerequisites 1. **Docker** must be installed and running (used by Supabase CLI internally) 2. **Supabase CLI** — installed automatically via `pnpm exec supabase` #### Test Scripts Overview | Script | Description | What it does | | ----------------- | --------------------------------- | ----------------------------------------------------------------- | | `test:storage` | **Complete test workflow** | Runs the full test cycle: clean → start infra → run tests → clean | | `test:suite` | **Jest tests only** | Runs Jest tests with coverage (requires infra to be running) | | `test:infra` | **Start test infrastructure** | Starts Supabase CLI stack (PostgreSQL, Storage API, Kong, etc.) | | `test:clean-post` | **Stop and clean infrastructure** | Stops the Supabase CLI stack | #### Running Tests ##### Option 1: Complete Test Run (Recommended) This handles everything automatically - starting infrastructure, running tests, and cleaning up: ```bash # From monorepo root pnpm nx test:storage storage-js ``` This command will: 1. Stop any existing test containers 2. Build and start fresh test infrastructure 3. Wait for services to be ready 4. Run all Jest tests with coverage 5. Clean up all containers after tests complete ##### Option 2: Manual Infrastructure Management Useful for development when you want to run tests multiple times without restarting Docker: ```bash # Step 1: Start the test infrastructure # From root pnpm nx test:infra storage-js # This starts: PostgreSQL, Storage API, Kong Gateway, and imgproxy # Step 2: Run tests (can run multiple times) pnpm nx test:suite storage-js # Step 3: When done, clean up the infrastructure pnpm nx test:clean-post storage-js ``` ##### Option 3: Development Mode For actively developing and debugging tests: ```bash # Start infrastructure once (from root) pnpm nx test:infra storage-js # Run tests in watch mode pnpm nx test:suite storage-js --watch # Clean up when done pnpm nx test:clean-post storage-js ``` #### Test Infrastructure Details The test infrastructure is managed via the Supabase CLI (`pnpm exec supabase start --workdir test`), which starts a local Supabase stack defined by the config in `test/`. This includes PostgreSQL, the Storage API, Kong Gateway, and supporting services. #### Common Issues and Solutions | Issue | Solution | | --------------------------------- | ------------------------------------------------------------------------------------------------- | | Port conflicts | Another service is using a required port. Run `pnpm nx test:clean-post storage-js` then try again | | "request failed, reason:" errors | Infrastructure isn't running. Run `pnpm nx test:infra storage-js` first | | Tests fail with connection errors | Ensure Docker is running (Supabase CLI requires Docker) | | Stack already running | Run `pnpm nx test:clean-post storage-js` to stop it before restarting | #### Understanding Test Failures - **StorageUnknownError with "request failed"**: Infrastructure not running - **Snapshot failures**: Expected test data has changed — review and update snapshots if needed ### Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes.
-
-
supabase-js
-
README.md 11.7 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase JS SDK</h1> <h3 align="center">Isomorphic JavaScript SDK for Supabase - combining Auth, Database, Storage, Functions, and Realtime.</h3> <p align="center"> <a href="https://supabase.com/docs/guides/getting-started">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/start">Reference Docs</a> · <a href="https://supabase.github.io/supabase-js/supabase-js/v2/spec.json">TypeDoc</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/supabase-js) [](#license) [](https://pkg.pr.new/~/supabase/supabase-js) </div> ## Usage First of all, you need to install the library: ```sh npm install @supabase/supabase-js ``` Then you're able to import the library and establish the connection with the database: ```js import { createClient } from '@supabase/supabase-js' // Create a single supabase client for interacting with your database const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key') ``` ### UMD You can use plain `<script>`s to import supabase-js from CDNs, like: ```html <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script> ``` or even: ```html <script src="https://unpkg.com/@supabase/supabase-js@2"></script> ``` Then you can use it from a global `supabase` variable: ```html <script> const { createClient } = supabase const _supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key') console.log('Supabase Instance: ', _supabase) // ... </script> ``` ### ESM You can use `<script type="module">` to import supabase-js from CDNs, like: ```html <script type="module"> import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm' const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key') console.log('Supabase Instance: ', supabase) // ... </script> ``` ### Deno You can use supabase-js in the Deno runtime via [JSR](https://jsr.io/@supabase/supabase-js): ```js import { createClient } from 'jsr:@supabase/supabase-js@2' ``` ### Custom `fetch` implementation `supabase-js` uses the runtime's global `fetch` to make HTTP requests, but an alternative `fetch` implementation can be provided as an option. This is useful in environments where the global `fetch` is unavailable or where you want to customize request behavior: ```js import { createClient } from '@supabase/supabase-js' // Provide a custom `fetch` implementation as an option const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key', { global: { fetch: (...args) => fetch(...args), }, }) ``` ### Distributed Tracing with OpenTelemetry The Supabase JS SDK can attach W3C/OpenTelemetry trace context headers (`traceparent`, `tracestate`, `baggage`) to outgoing requests, enabling end-to-end request tracing from your client application through Supabase services. Trace propagation is **opt-in** and disabled by default. When enabled, headers are only attached to requests targeting Supabase domains (`*.supabase.co`, `*.supabase.in`, `localhost`). #### Enable trace propagation Opting in takes two steps: install `@opentelemetry/api`, and load the tracing runtime by importing the `@supabase/supabase-js/tracing` subpath once at your application entry point. The main bundle contains no OpenTelemetry code — the subpath import is what wires it up. ```js import '@supabase/supabase-js/tracing' import { createClient } from '@supabase/supabase-js' import { trace } from '@opentelemetry/api' const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { tracePropagation: true, }) const tracer = trace.getTracer('my-app') await tracer.startActiveSpan('fetch-users', async (span) => { // This request now includes the active trace context. const { data, error } = await supabase.from('users').select('*') span.end() }) ``` The subpath imports `@opentelemetry/api` directly, so module resolution fails loudly if it is not installed. If `tracePropagation` is enabled without the subpath import, the SDK logs a one-time warning and sends requests without trace headers; if no active context exists at request time, it silently no-ops. Trace propagation is not available via the CDN/UMD build (`https://cdn.jsdelivr.net/.../supabase.js`) — there is no way to load the tracing runtime there. #### Advanced configuration ```typescript interface TracePropagationOptions { // Enable trace propagation (default: false). enabled?: boolean // Respect upstream sampling decisions (default: true). // When true, non-sampled requests carry only `traceparent` (flag preserved, // so nothing is recorded downstream) — Supabase logs still get a trace_id, // while `tracestate` and `baggage` are withheld. respectSamplingDecision?: boolean } ``` ```js // Always propagate the full trace context, even for non-sampled traces. const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { tracePropagation: { enabled: true, respectSamplingDecision: false }, }) ``` ## Support Policy This section outlines the scope of support for various runtime environments in Supabase JavaScript client. ### Node.js We only support Node.js versions that are in **Active LTS** or **Maintenance** status as defined by the [official Node.js release schedule](https://nodejs.org/en/about/previous-releases#release-schedule). This means we support versions that are currently receiving long-term support and critical bug fixes. When a Node.js version reaches end-of-life and is no longer in Active LTS or Maintenance status, Supabase will drop it in a **minor release**, and **this won't be considered a breaking change**. > ⚠️ **Node.js 18 Deprecation Notice** > > Node.js 18 reached end-of-life on April 30, 2025. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/37217), support for Node.js 18 was dropped in version `2.79.0`. > > If you must use Node.js 18, please use version `2.78.0`, which is the last version that supported Node.js 18. > ⚠️ **Node.js 20 Deprecation Notice** > > Node.js 20 reached end-of-life on April 30, 2026. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/45715), support for Node.js 20 was dropped in version `2.110.0`. > > If you must use Node.js 20, please use version `2.109.0`, which is the last version that supported Node.js 20. ### Deno We support Deno versions that are currently receiving active development and security updates. We follow the [official Deno release schedule](https://docs.deno.com/runtime/fundamentals/stability_and_releases/) and only support versions from the `stable` and `lts` release channels. When a Deno version reaches end-of-life and is no longer receiving security updates, Supabase will drop it in a **minor release**, and **this won't be considered a breaking change**. ### Browsers All modern browsers are supported. We support browsers that provide native `fetch` API. For Realtime features, browsers must also support native `WebSocket` API. ### Bun We support Bun runtime environments. Bun provides native fetch support and is compatible with Node.js APIs. Since Bun does not follow a structured release schedule like Node.js or Deno, we support current stable versions of Bun and may drop support for older versions in minor releases without considering it a breaking change. ### React Native We support React Native environments with fetch polyfills provided by the framework. Since React Native does not follow a structured release schedule, we support current stable versions and may drop support for older versions in minor releases without considering it a breaking change. ### Cloudflare Workers We support Cloudflare Workers runtime environments. Cloudflare Workers provides native fetch support. Since Cloudflare Workers does not follow a structured release schedule, we support current stable versions and may drop support for older versions in minor releases without considering it a breaking change. ### Important Notes - **Experimental features**: Features marked as experimental may be removed or changed without notice ## Known Build Warnings ### `UNUSED_EXTERNAL_IMPORT` in Vite / Rollup / Nuxt When bundling your app, you may see warnings like: ``` "PostgrestError" is imported from external module "@supabase/postgrest-js" but never used in "...supabase-js/dist/index.mjs". "FunctionRegion", "FunctionsError", "FunctionsFetchError", "FunctionsHttpError" and "FunctionsRelayError" are imported from external module "@supabase/functions-js" but never used in "...". ``` **This is a false positive — your bundle is fine.** Here is why it happens: `@supabase/supabase-js` re-exports `PostgrestError`, `FunctionsError`, and related symbols so you can import them directly from `@supabase/supabase-js`. However, our build tool merges all imports from the same package into a single import statement in the built output: ```js // dist/index.mjs (simplified) import { PostgrestClient, PostgrestError } from '@supabase/postgrest-js' // ^ used internally ^ re-exported for you ``` Your bundler checks which names from that import are used _in the code body_, and flags `PostgrestError` as unused because it only appears in an `export` statement — not called or assigned. The export itself is the usage, but downstream bundlers don't track this correctly. This is a known Rollup/Vite limitation with re-exported external imports. **Nothing is broken.** Tree-shaking and bundle size are unaffected. To suppress the warning: **Vite / Rollup (`vite.config.js` or `rollup.config.js`):** ```js export default { build: { rollupOptions: { onwarn(warning, warn) { if (warning.code === 'UNUSED_EXTERNAL_IMPORT' && warning.exporter?.includes('@supabase/')) return warn(warning) }, }, }, } ``` **Nuxt (`nuxt.config.ts`):** ```ts export default defineNuxtConfig({ vite: { build: { rollupOptions: { onwarn(warning, warn) { if (warning.code === 'UNUSED_EXTERNAL_IMPORT' && warning.exporter?.includes('@supabase/')) return warn(warning) }, }, }, }, }) ``` ## Contributing We welcome contributions! Please see our [Contributing Guide](../../../CONTRIBUTING.md) for details on how to get started. For major changes or if you're unsure about something, please open an issue first to discuss your proposed changes. ### Building ```bash # From the monorepo root pnpm nx build supabase-js # Or with watch mode for development pnpm nx build supabase-js --watch ``` ### Testing There's a complete guide on how to set up your environment for running locally the `supabase-js` integration tests. Please refer to [TESTING.md](./TESTING.md). ## Badges [](https://coveralls.io/github/supabase/supabase-js?branch=master)
-
-
overview.md 9.2 KB
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg"> <img alt="Supabase Logo" width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/logo-preview.jpg"> </picture> </a> <h1 align="center">Supabase JS SDK</h1> <p align="center"> <a href="https://supabase.com/docs/guides/getting-started">Guides</a> · <a href="https://supabase.com/docs/reference/javascript/introduction">Reference Docs</a> </p> </p> <div align="center"> [](https://github.com/supabase/supabase-js/actions?query=branch%3Amaster) [](https://www.npmjs.com/package/@supabase/postgrest-js) [](#license) [](https://pkg.pr.new/~/supabase/supabase-js) </div> ## 📦 Libraries This monorepo contains the complete suite of Supabase JavaScript SDK: | Library | Description | | ---------------------------------------------------------- | ------------------------------------- | | **[@supabase/supabase-js](./packages/core/supabase-js)** | Main isomorphic SDK for Supabase | | **[@supabase/auth-js](./packages/core/auth-js)** | Authentication SDK | | **[@supabase/postgrest-js](./packages/core/postgrest-js)** | PostgREST SDK for database operations | | **[@supabase/realtime-js](./packages/core/realtime-js)** | Real-time subscriptions SDK | | **[@supabase/storage-js](./packages/core/storage-js)** | File storage SDK | | **[@supabase/functions-js](./packages/core/functions-js)** | Edge Functions SDK | ## Support Policy This section outlines the scope of support for various runtime environments in Supabase JavaScript client. ### Node.js We only support Node.js versions that are in **Active LTS** or **Maintenance** status as defined by the [official Node.js release schedule](https://nodejs.org/en/about/previous-releases#release-schedule). This means we support versions that are currently receiving long-term support and critical bug fixes. When a Node.js version reaches end-of-life and is no longer in Active LTS or Maintenance status, Supabase will drop it in a **minor release**, and **this won't be considered a breaking change**. > ⚠️ **Node.js 18 Deprecation Notice** > > Node.js 18 reached end-of-life on April 30, 2025. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/37217), support for Node.js 18 was dropped in version `2.79.0`. > > If you must use Node.js 18, please use version `2.78.0`, which is the last version that supported Node.js 18. > ⚠️ **Node.js 20 Deprecation Notice** > > Node.js 20 reached end-of-life on April 30, 2026. As announced in [our deprecation notice](https://github.com/orgs/supabase/discussions/45715), support for Node.js 20 was dropped in version `2.110.0`. > > If you must use Node.js 20, please use version `2.109.0`, which is the last version that supported Node.js 20. ### Deno We support Deno versions that are currently receiving active development and security updates. We follow the [official Deno release schedule](https://docs.deno.com/runtime/fundamentals/stability_and_releases/) and only support versions from the `stable` and `lts` release channels. When a Deno version reaches end-of-life and is no longer receiving security updates, Supabase will drop it in a **minor release**, and **this won't be considered a breaking change**. ### Browsers All modern browsers are supported. We support browsers that provide native `fetch` API. For Realtime features, browsers must also support native `WebSocket` API. ### Bun We support Bun runtime environments. Bun provides native fetch support and is compatible with Node.js APIs. Since Bun does not follow a structured release schedule like Node.js or Deno, we support current stable versions of Bun and may drop support for older versions in minor releases without considering it a breaking change. ### React Native We support React Native environments with fetch polyfills provided by the framework. Since React Native does not follow a structured release schedule, we support current stable versions and may drop support for older versions in minor releases without considering it a breaking change. ### Cloudflare Workers We support Cloudflare Workers runtime environments. Cloudflare Workers provides native fetch support. Since Cloudflare Workers does not follow a structured release schedule, we support current stable versions and may drop support for older versions in minor releases without considering it a breaking change. ### Important Notes - **Experimental features**: Features marked as experimental may be removed or changed without notice - **Build warnings**: If you see `UNUSED_EXTERNAL_IMPORT` warnings from Vite/Nuxt, see the [supabase-js README](./packages/core/supabase-js/README.md#known-build-warnings) — these are false positives ## 🚀 Quick Start ### Installation ```bash npm install @supabase/supabase-js ``` Read more in each package's README file. ## 🤝 Contributing We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) for details. ### Quick Contribution Steps 1. **Fork the repository** 2. **Create a feature branch** (`git checkout -b feature/amazing-feature`) 3. **Make your changes** and add tests 4. **Run tests** (`pnpm nx affected --target=test`) 5. **Commit your changes** (`pnpm commit`) 6. **Push to your branch** (`git push origin feature/amazing-feature`) 7. **Open a Pull Request** ### Development Guidelines - Follow [conventional commits](https://www.conventionalcommits.org/) for commit messages - Add tests for new functionality - Update documentation for API changes - Run `pnpm nx format` before committing - Ensure all tests pass with `pnpm nx affected --target=test` ## 🧪 Testing Testing varies per package. See the top-level [TESTING.md](docs/TESTING.md) for an overview and links to package-specific guides. ## 📚 Documentation ### API Documentation - **[Auth SDK](./packages/core/auth-js/README.md)** - Authentication and user management - **[Database SDK](./packages/core/postgrest-js/README.md)** - Database queries and operations - **[Realtime SDK](./packages/core/realtime-js/README.md)** - Real-time subscriptions - **[Storage SDK](./packages/core/storage-js/README.md)** - File upload and management - **[Functions SDK](./packages/core/functions-js/README.md)** - Edge Functions invocation - **[Main SDK](./packages/core/supabase-js/README.md)** - Combined SDK ### Architecture Documentation - **[Contributing](./CONTRIBUTING.md)** - Development guidelines - **[Release Workflows](./docs/RELEASE.md)** - Release and publishing process - **[Migration Guide](./docs/MIGRATION.md)** - Cross-cutting migration notes (per-package migrations live alongside each package under `packages/core/<package>/migrations/`) - **[Security Policy](https://github.com/supabase/supabase-js/security/policy)** - Vulnerability reporting and disclosure policy - **[Securing your npm installs](https://supabase.com/docs/guides/security/npm-security)** - Consumer-side guide to defending your install against npm supply-chain attacks ## 🔐 Verifying provenance attestations You can verify registry signatures and provenance attestations for installed packages using the npm CLI: ```bash npm audit signatures ``` Quick example for a single package install: ```bash npm install @supabase/auth-js npm audit signatures ``` Example output: ```text audited 1 package in 0s 1 package has a verified registry signature ``` Because provenance attestations are a new capability, security features may evolve over time. Ensure you are using the latest npm CLI to verify attestation signatures reliably. This may require updating npm beyond the version bundled with Node.js. For a broader checklist — minimum release age, lockfile hygiene, blocking exotic transitive deps, lifecycle script controls, and what to do if you suspect a compromise — see [Securing your npm installs](https://supabase.com/docs/guides/security/npm-security). ## 📄 License This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details. ## 🆘 Support - **Documentation**: [supabase.com/docs](https://supabase.com/docs) - **Community**: [GitHub Discussions](https://github.com/supabase/supabase/discussions) - **Issues**: [GitHub Issues](https://github.com/supabase/supabase-js/issues) - **Discord**: [Supabase Discord](https://discord.supabase.com) --- <div align="center"> **[Website](https://supabase.com) • [Documentation](https://supabase.com/docs) • [Community](https://github.com/supabase/supabase/discussions) • [Twitter](https://twitter.com/supabase)** </div>
-
-
SKILL.md 6.3 KB
--- name: supabase-js description: This skill should be used when user asks to "use supabase-js", "query Supabase database", "supabase auth", "supabase storage", "supabase realtime", "supabase edge functions", or works with the @supabase/supabase-js JavaScript/TypeScript SDK. references: - supabase-js - auth-js - postgrest-js - storage-js license: MIT --- # Supabase JavaScript SDK Skill Skill for building applications with the `@supabase/supabase-js` SDK. Covers Auth, Database (PostgREST), Storage, Realtime, and Edge Functions. The SDK docs at https://supabase.com/docs/reference/javascript are the source of truth. The reference files alongside this skill contain source code and READMEs extracted from the monorepo for quick lookup. ## Setup ```bash npm install @supabase/supabase-js ``` ```typescript import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key') ``` For type-safe queries, generate types from your database schema: ```bash supabase gen types typescript --project-id your-project-id > database.types.ts ``` ```typescript import { createClient } from '@supabase/supabase-js' import type { Database } from './database.types' const supabase = createClient<Database>(SUPABASE_URL, SUPABASE_ANON_KEY) ``` ## Quick Decision Trees ### "I need to query data" ``` Database query? ├─ Select rows → supabase.from('table').select('*') ├─ Filter rows → .select().eq('col', val) / .gt() / .lt() / .in() / .like() ├─ Join tables → .select('*, other_table(*)') or .select('*, other_table!fk(*)') ├─ Insert → supabase.from('table').insert({ col: val }) ├─ Upsert → supabase.from('table').upsert({ id: 1, col: val }) ├─ Update → supabase.from('table').update({ col: val }).eq('id', 1) ├─ Delete → supabase.from('table').delete().eq('id', 1) ├─ Call RPC function → supabase.rpc('function_name', { arg: val }) ├─ Count rows → .select('*', { count: 'exact', head: true }) ├─ Pagination → .range(0, 9) or .limit(10).offset(20) └─ Order → .order('created_at', { ascending: false }) ``` ### "I need authentication" ``` Auth? ├─ Email/password sign up → supabase.auth.signUp({ email, password }) ├─ Email/password sign in → supabase.auth.signInWithPassword({ email, password }) ├─ OAuth (Google, GitHub, etc.) → supabase.auth.signInWithOAuth({ provider: 'google' }) ├─ Magic link → supabase.auth.signInWithOtp({ email }) ├─ Phone OTP → supabase.auth.signInWithOtp({ phone }) ├─ Sign out → supabase.auth.signOut() ├─ Get current user → supabase.auth.getUser() ├─ Get session → supabase.auth.getSession() ├─ Listen to auth changes → supabase.auth.onAuthStateChange((event, session) => {}) ├─ Reset password → supabase.auth.resetPasswordForEmail(email) ├─ Update user → supabase.auth.updateUser({ data: { name: 'New' } }) └─ Admin operations → supabase.auth.admin.listUsers() / .deleteUser(id) ``` ### "I need file storage" ``` Storage? ├─ Upload file → supabase.storage.from('bucket').upload('path/file.png', file) ├─ Download file → supabase.storage.from('bucket').download('path/file.png') ├─ Get public URL → supabase.storage.from('bucket').getPublicUrl('path/file.png') ├─ Create signed URL → supabase.storage.from('bucket').createSignedUrl('path', 3600) ├─ List files → supabase.storage.from('bucket').list('folder') ├─ Move file → supabase.storage.from('bucket').move('old/path', 'new/path') ├─ Remove file → supabase.storage.from('bucket').remove(['path/file.png']) ├─ Create bucket → supabase.storage.createBucket('name', { public: false }) └─ List buckets → supabase.storage.listBuckets() ``` ### "I need realtime" ``` Realtime? ├─ Listen to DB changes → supabase.channel('name') │ .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, handler) │ .subscribe() ├─ Broadcast messages → channel.send({ type: 'broadcast', event: 'cursor', payload: { x, y } }) ├─ Listen to broadcasts → .on('broadcast', { event: 'cursor' }, handler) ├─ Presence (who's online) → channel.track({ user_id, online_at }) │ .on('presence', { event: 'sync' }, () => channel.presenceState()) ├─ Unsubscribe → supabase.removeChannel(channel) └─ Unsubscribe all → supabase.removeAllChannels() ``` ### "I need edge functions" ``` Edge Functions? ├─ Invoke function → supabase.functions.invoke('function-name', { body: { key: 'val' } }) ├─ With custom headers → .invoke('fn', { headers: { 'x-custom': 'val' }, body }) └─ Set region → .invoke('fn', { body, region: 'us-east-1' }) ``` ## Common Patterns ### Server-side with service role key ```typescript // Server-side only - bypasses RLS const supabase = createClient(SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, { auth: { persistSession: false } }) ``` ### React/Next.js auth ```typescript import { createClient } from '@supabase/supabase-js' import { useEffect, useState } from 'react' const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY) function useUser() { const [user, setUser] = useState(null) useEffect(() => { supabase.auth.getUser().then(({ data }) => setUser(data.user)) const { data: { subscription } } = supabase.auth.onAuthStateChange( (_, session) => setUser(session?.user ?? null) ) return () => subscription.unsubscribe() }, []) return user } ``` ### Typed database queries ```typescript // Generated types give autocomplete for table names, column names, and return types const { data, error } = await supabase .from('profiles') // autocompleted table name .select('id, username') // autocompleted columns .eq('id', userId) // type-safe filter .single() // returns single row or error // data is typed as { id: string; username: string } | null ``` ## Package Index | Package | Sub-client | Reference | |---------|-----------|-----------| | `@supabase/supabase-js` | `createClient()` | `references/supabase-js/` | | `@supabase/auth-js` | `.auth` | `references/auth-js/` | | `@supabase/postgrest-js` | `.from()`, `.rpc()` | `references/postgrest-js/` | | `@supabase/realtime-js` | `.channel()`, `.realtime` | `references/realtime-js/` | | `@supabase/storage-js` | `.storage` | `references/storage-js/` | | `@supabase/functions-js` | `.functions` | `references/functions-js/` |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.