Jesse A. Green / notebook

Supabase User Guide

Generated May 2026 from supabase/supabase at a5f4a59

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Quick Start

Supabase is an open-source Firebase alternative that provides a full backend platform built on Postgres. It offers a managed database, authentication, real-time subscriptions, file storage, edge functions, and auto-generated REST and GraphQL APIs — all accessible through client SDKs or a web dashboard called Supabase Studio.

Key features:

  • Postgres database with Row Level Security (RLS), extensions, and full SQL access
  • Authentication supporting email/password, magic links, phone OTP, and 20+ OAuth providers
  • Realtime subscriptions via WebSockets for Postgres changes, broadcast, and presence
  • Storage for files with CDN, image transformations, and resumable uploads
  • Edge Functions — Deno-based serverless functions deployed globally
  • Auto-generated APIs — PostgREST (REST) and pg_graphql (GraphQL) from your schema
  • Supabase Studio — web-based dashboard for managing your project

Prerequisites: A Supabase account at supabase.com, or Docker for self-hosting.

Get started in 60 seconds:

npm install @supabase/supabase-js
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  'https://your-project.supabase.co',
  'your-anon-key'
)

// Query your database
const { data, error } = await supabase
  .from('todos')
  .select('*')
[ { id: 1, task: 'Buy groceries', is_complete: false } ]

Tip

Find your project URL and anon key in the Supabase Dashboard under Settings > API. The anon key is safe to use in client-side code — Row Level Security protects your data.

What to try next:

  • Set up authentication (see "Authentication" in Core Usage)
  • Create database tables in the Studio Table Editor
  • Add real-time subscriptions to your app
  • See the Admin Guide for self-hosting and architecture details

2. Installation

System requirements

Requirement Minimum
Node.js 18+ (22+ for monorepo development)
Package manager npm, yarn, pnpm, or bun
Browser Modern browser for Studio access

Client SDK installation

npm

npm install @supabase/supabase-js

yarn

yarn add @supabase/supabase-js

pnpm

pnpm add @supabase/supabase-js

bun

bun add @supabase/supabase-js

Important

The @supabase/supabase-js package (v2.103.2 as of this source) bundles @supabase/auth-js, @supabase/postgrest-js, @supabase/realtime-js, and @supabase/storage-js. You do not need to install these separately unless you want to use them standalone.

Supabase CLI installation

The Supabase CLI is distributed separately via the supabase npm package. It manages local development, migrations, and deployments.

npm

npm install -D supabase

Homebrew

brew install supabase/tap/supabase

Verification

npx supabase --version
2.76.10
import { createClient } from '@supabase/supabase-js'
console.log('Supabase JS loaded successfully')

Self-hosting with Docker

For self-hosted deployments, Supabase provides a complete Docker Compose setup:

git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env
docker compose pull
docker compose up -d

Warning

The default .env.example ships with example secrets (JWT secret, anon key, service role key). You must generate new secrets before exposing the instance to any network. See the Admin Guide for secure configuration.

After startup, access Supabase Studio at http://localhost:8000 with the dashboard credentials from your .env file.

Install troubleshooting

Error: Cannot find module '@supabase/supabase-js'

Cause: Package not installed or wrong node_modules resolution.

Solution:

  1. Run npm install @supabase/supabase-js again
  2. Check your package.json includes the dependency
  3. Delete node_modules and package-lock.json, then reinstall

Prevention: Pin the version in package.json and use a lockfile.

Error: pnpm: command not found (monorepo development)

Cause: The Supabase monorepo requires pnpm 10.24 specifically.

Solution:

npm install -g pnpm@10.24

Prevention: The root package.json enforces pnpm via a preinstall script (npx only-allow pnpm).

Error: Docker containers fail to start

Cause: Missing .env file or port conflicts.

Solution:

  1. Verify .env exists in docker/ directory
  2. Check for port conflicts on 8000, 5432, 9000
  3. Run docker compose logs to identify the failing service

Prevention: Always copy .env.example before first start.


3. Configuration

Client initialization

Every Supabase client requires two values: your project URL and your anon key:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)

Common environment variables

Variable Purpose Example
NEXT_PUBLIC_SUPABASE_URL Project API URL https://xyzproject.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY Public (anon) API key eyJhbGciOiJI...
SUPABASE_SERVICE_ROLE_KEY Server-side admin key eyJhbGciOiJI...
EXPO_PUBLIC_SUPABASE_URL Expo/React Native project URL https://xyzproject.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY Expo/React Native anon key eyJhbGciOiJI...
VUE_APP_SUPABASE_URL Vue/Ionic project URL https://xyzproject.supabase.co
VUE_APP_SUPABASE_KEY Vue/Ionic anon key eyJhbGciOiJI...
REACT_APP_SUPABASE_URL Create React App project URL https://xyzproject.supabase.co
REACT_APP_SUPABASE_ANON_KEY Create React App anon key eyJhbGciOiJI...

Warning

The SUPABASE_SERVICE_ROLE_KEY bypasses Row Level Security entirely. Never expose it in client-side code — use it only in server-side environments (API routes, edge functions, backend services).

Framework-specific SSR setup

Supabase provides a dedicated package for server-side rendering:

npm install @supabase/ssr

This package (@supabase/ssr v0.10.2) handles cookie-based auth for Next.js, SvelteKit, Nuxt, and other SSR frameworks.

Local development configuration

The local Supabase CLI uses supabase/config.toml to configure services:

[api]
port = 54321
schemas = ["public", "storage", "graphql_public"]
extra_search_path = ["public", "extensions"]
max_rows = 1000

[db]
port = 54322
major_version = 15

[studio]
port = 54323

[auth]
site_url = "http://localhost:3000"
jwt_expiry = 3600
enable_signup = true

[auth.email]
enable_signup = true
double_confirm_changes = true
enable_confirmations = false

[storage]
file_size_limit = "50MiB"

Note

The schemas array under [api] controls which Postgres schemas are exposed via the REST API. The public and storage schemas are always included.

For the complete configuration reference including all auth providers, storage backends, and deployment settings, see the Admin Guide.


4. Core Usage

Database queries

Supabase auto-generates a REST API from your Postgres schema via PostgREST. Use the JavaScript client to query tables:

Select rows:

const { data, error } = await supabase
  .from('countries')
  .select('id, name, population')
  .order('name')

Insert rows:

const { data, error } = await supabase
  .from('countries')
  .insert({ name: 'Japan', population: 125800000 })
  .select()

Update rows:

const { data, error } = await supabase
  .from('countries')
  .update({ population: 125700000 })
  .eq('name', 'Japan')
  .select()

Delete rows:

const { data, error } = await supabase
  .from('countries')
  .delete()
  .eq('id', 42)

Filtering:

const { data } = await supabase
  .from('countries')
  .select('*')
  .gte('population', 1000000)
  .ilike('name', '%land%')
  .limit(10)

Note

The API respects Row Level Security policies. The default max_rows is 1000 (configurable in supabase/config.toml under [api]). Use .range() for pagination beyond this limit.

Authentication

Supabase Auth (GoTrue) supports multiple authentication methods.

Email/password signup:

const { data, error } = await supabase.auth.signUp({
  email: '[email removed]',
  password: 'secure-password',
})

Email/password login:

const { data, error } = await supabase.auth.signInWithPassword({
  email: '[email removed]',
  password: 'secure-password',
})

OAuth login:

const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'github',
})

Supported OAuth providers: Apple, Azure, Bitbucket, Discord, Facebook, Figma, GitHub, GitLab, Google, Keycloak, LinkedIn, LinkedIn OIDC, Notion, Twitch, Twitter, Slack, Spotify, WorkOS, and Zoom.

Sign out:

const { error } = await supabase.auth.signOut()

Listen to auth state changes:

supabase.auth.onAuthStateChange((event, session) => {
  console.log(event, session)
})

Tip

Use supabase.auth.getUser() rather than supabase.auth.getSession() for server-side validation — getUser() verifies the JWT with the auth server, while getSession() only reads the local session.

Realtime subscriptions

Subscribe to database changes, broadcast messages, or track user presence.

Listen to INSERT events:

const channel = supabase
  .channel('todos')
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'todos',
  }, (payload) => {
    console.log('New todo:', payload.new)
  })
  .subscribe()

Broadcast messages:

const channel = supabase.channel('room-1')

// Send
channel.send({
  type: 'broadcast',
  event: 'cursor',
  payload: { x: 100, y: 200 },
})

// Receive
channel.on('broadcast', { event: 'cursor' }, (payload) => {
  console.log('Cursor position:', payload)
})

Presence (track online users):

const channel = supabase.channel('online-users')

channel.on('presence', { event: 'sync' }, () => {
  const state = channel.presenceState()
  console.log('Online users:', state)
})

channel.subscribe(async (status) => {
  if (status === 'SUBSCRIBED') {
    await channel.track({ user_id: '123', online_at: new Date() })
  }
})

Note

Realtime requires the table to be added to the supabase_realtime publication. In SQL: alter publication supabase_realtime add table your_table;

Storage

Upload, download, and manage files with Supabase Storage.

Upload a file:

const { data, error } = await supabase.storage
  .from('avatars')
  .upload('public/avatar.png', file, {
    cacheControl: '3600',
    upsert: false,
  })

Download a file:

const { data, error } = await supabase.storage
  .from('avatars')
  .download('public/avatar.png')

Get a public URL:

const { data } = supabase.storage
  .from('avatars')
  .getPublicUrl('public/avatar.png')

List files in a bucket:

const { data, error } = await supabase.storage
  .from('avatars')
  .list('public', { limit: 100, offset: 0 })

The default file size limit is 50MiB (configurable in supabase/config.toml under [storage]).

Edge Functions

Invoke Deno-based serverless functions:

const { data, error } = await supabase.functions.invoke('my-function', {
  body: { name: 'World' },
})

Edge Functions are deployed via the Supabase CLI:

npx supabase functions deploy my-function

Important

By default, Edge Functions require a valid JWT. To make a function publicly accessible, set verify_jwt = false in your supabase/config.toml under [functions.function-name]. The monorepo's own search-embeddings function uses this pattern.


5. Common Tasks

Set up a new project with Next.js

Goal: Create a Next.js app connected to Supabase with authentication.

Prerequisites: Node.js 18+, a Supabase project.

Steps:

  1. Create a Next.js app:

    npx create-next-app my-app
    cd my-app
    
  2. Install Supabase packages:

    npm install @supabase/supabase-js @supabase/ssr
    
  3. Add environment variables to .env.local:

    NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
    
  4. Create a Supabase client utility:

    // lib/supabase.js
    import { createClient } from '@supabase/supabase-js'
    
    export const supabase = createClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
    )
    
  5. Use it in a component:

    const { data } = await supabase.from('todos').select('*')
    

Verify: Data loads from your Supabase project in the browser.

Create a user profile system with avatar uploads

Goal: Set up a profiles table with RLS and avatar storage.

Steps:

  1. Create the profiles table in SQL Editor:

    create table profiles (
      id uuid references auth.users not null primary key,
      updated_at timestamp with time zone,
      username text unique,
      avatar_url text,
      website text,
      constraint username_length check (char_length(username) >= 3)
    );
    
    alter table profiles enable row level security;
    
    create policy "Users can view their own profile."
      on profiles for select
      using (auth.uid() = id);
    
    create policy "Users can insert their own profile."
      on profiles for insert
      with check (auth.uid() = id);
    
    create policy "Users can update their own profile."
      on profiles for update
      using (auth.uid() = id);
    
  2. Create a storage bucket for avatars:

    insert into storage.buckets (id, name)
    values ('avatars', 'avatars');
    
    create policy "Avatar images are publicly accessible."
      on storage.objects for select
      using (bucket_id = 'avatars');
    
    create policy "Anyone can upload an avatar."
      on storage.objects for insert
      with check (bucket_id = 'avatars');
    
  3. Set up realtime for profile updates:

    alter publication supabase_realtime add table profiles;
    
  4. Query and update the profile from your app:

    // Fetch profile
    const { data } = await supabase
      .from('profiles')
      .select('username, avatar_url, website')
      .eq('id', user.id)
      .single()
    
    // Update profile
    await supabase
      .from('profiles')
      .upsert({ id: user.id, username: 'newname', updated_at: new Date() })
    

Verify: Users can view and edit only their own profile.

If it fails: Check that RLS policies are active with select * from pg_policies where tablename = 'profiles';

Enable real-time for a table

Goal: Receive live updates when rows change.

Steps:

  1. Enable the realtime publication:

    alter publication supabase_realtime add table todos;
    
  2. Subscribe in your client:

    supabase
      .channel('todos-changes')
      .on('postgres_changes', {
        event: '*',
        schema: 'public',
        table: 'todos',
      }, (payload) => {
        console.log('Change:', payload)
      })
      .subscribe()
    

Verify: Insert a row in the Studio Table Editor and confirm the subscription fires.

If it fails: Check that RLS allows SELECT for the subscribing user role.

Set up local development

Goal: Develop against a local Supabase stack.

Steps:

  1. Initialize Supabase in your project:

    npx supabase init
    
  2. Start the local stack:

    npx supabase start
    
  3. The CLI outputs local URLs and keys:

    API URL: http://127.0.0.1:54321
    Studio URL: http://127.0.0.1:54323
    Inbucket URL: http://127.0.0.1:54324
    anon key: eyJ...
    service_role key: eyJ...
    
  4. Point your app to the local instance:

    NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
    NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
    

Verify: Open Studio at http://127.0.0.1:54323.

Tip

Use npx supabase db reset to rerun migrations and seed data. Use npx supabase status --output json > keys.json to programmatically capture keys. The local email testing server (Inbucket) at port 54324 captures all auth emails.

Build a Slack clone with real-time messaging

Goal: Create a multi-channel chat application.

The examples/slack-clone/ directory provides a complete Next.js implementation. The key patterns:

  1. Channels table with RLS for authorized access
  2. Messages table joined to user profiles
  3. Realtime subscriptions for new messages per channel
  4. Presence tracking for online users in each channel
// Subscribe to new messages in a channel
const channel = supabase
  .channel(`room:${channelId}`)
  .on('postgres_changes', {
    event: 'INSERT',
    schema: 'public',
    table: 'messages',
    filter: `channel_id=eq.${channelId}`,
  }, (payload) => {
    setMessages(prev => [...prev, payload.new])
  })
  .subscribe()

Integrate with Clerk for external authentication

Goal: Use Clerk as an external auth provider with Supabase.

The examples/clerk/ directory demonstrates this pattern. It includes a Supabase migration (examples/clerk/supabase/migrations/) that creates a requesting_user_id() helper function to extract the user ID from Clerk JWTs.

  1. Configure Clerk JWT templates to include Supabase claims
  2. Create a Supabase client that passes the Clerk JWT:
    const supabase = createClient(url, anonKey, {
      global: {
        headers: { Authorization: `Bearer ${clerkToken}` },
      },
    })
    

Implement caching with React Query

Goal: Use TanStack React Query for client-side caching of Supabase data.

The examples/caching/with-react-query-nextjs-14/ directory shows the pattern:

import { useQuery } from '@tanstack/react-query'

function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: async () => {
      const { data, error } = await supabase.from('todos').select('*')
      if (error) throw error
      return data
    },
  })
}

Set up multi-factor authentication (Flutter)

Goal: Add MFA to a Flutter app.

The examples/auth/flutter-mfa/ directory provides a complete implementation including:

  1. Enroll a TOTP factor after sign-in
  2. Challenge verification flow
  3. UI for entering the 6-digit code

Deploy edge functions with WASM modules

Goal: Use WebAssembly modules inside Edge Functions.

The examples/edge-functions/supabase/functions/wasm-modules/ directory demonstrates loading and calling Rust-compiled WASM within a Deno Edge Function:

// src/lib.rs
#[no_mangle]
pub extern "C" fn add(a: u32, b: u32) -> u32 {
    a + b
}

Use OAuth authorization flow for third-party apps

Goal: Build an app that authenticates via Supabase as an OAuth 2.0 provider.

The examples/oauth-app-authorization-flow/ provides a Hono-based example with /callback handling:

// Handle the OAuth callback
app.get('/callback', async (c) => {
  const code = c.req.query('code')
  // Exchange code for tokens
})

Note

Issue #45006 reports that the OAuth 2.1 consent example documentation references redirect_to when the actual response property is redirect_url. Use redirect_url as shown in the source code.


6. Troubleshooting

Diagnostic decision tree

Problem with Supabase?
├── Can't connect to the API?
│   ├── Check project URL and API key are correct
│   ├── Verify the project is not paused (Dashboard > Settings)
│   └── Check DNS resolution (issue #44977)
├── Auth not working?
│   ├── Check redirect URLs in Dashboard > Auth > URL Configuration
│   ├── Verify OAuth provider credentials
│   └── Check regional connectivity (issue #45002)
├── Realtime not receiving events?
│   ├── Table added to supabase_realtime publication?
│   ├── RLS policies allow SELECT for the subscribing user?
│   └── Check WebSocket connection in browser DevTools
├── Slow queries?
│   ├── Add indexes for frequently filtered columns
│   ├── Check query plan with EXPLAIN ANALYZE
│   └── Review RLS policy complexity
└── Self-hosting issues?
    ├── All containers running? docker compose ps
    ├── .env file present with valid secrets?
    └── Check service logs: docker compose logs <service>

Error: Failed to fetch on API calls

Cause: Network connectivity issue, project paused, or DNS resolution failure. Community reports of regional connectivity problems (issue #44978).

Solution:

  1. Verify your project URL resolves: nslookup your-project.supabase.co
  2. Check the Supabase status page
  3. If self-hosting, verify all Docker containers are healthy: docker compose ps

Prevention: Implement retry logic with exponential backoff in production apps.

Error: Discord OAuth consistently slow (5+ seconds)

Cause: GoTrue auth worker latency for specific OAuth providers (issue #45014).

Solution:

  1. This is a known platform issue being investigated
  2. Implement a loading state in your UI during OAuth redirects
  3. Check if the issue persists across different project regions

Error: Functions deploy returns 500 (internal error)

Cause: Internal server error during function deployment, potentially specific to certain function slugs (issue #45013).

Solution:

  1. Retry the deployment after a brief wait
  2. Test the function locally first: npx supabase functions serve my-function
  3. Verify the function name doesn't conflict with reserved names
  4. Check function dependencies compile cleanly

Prevention: Always test functions locally with supabase functions serve before deploying.

Cause: Password reset flow creates an authenticated session before the user changes their password (issue #32681).

Solution:

  1. Handle the PASSWORD_RECOVERY event explicitly in onAuthStateChange:
    supabase.auth.onAuthStateChange((event, session) => {
      if (event === 'PASSWORD_RECOVERY') {
        // Redirect to password change form, NOT to protected routes
      }
    })
    
  2. Implement a dedicated password reset page that checks the token type

Prevention: Always handle PASSWORD_RECOVERY separately from SIGNED_IN.

Error: Phone Auth not enabling despite correct Twilio credentials

Cause: Configuration format or credential mismatch (issue #44966).

Solution:

  1. Verify Twilio Account SID starts with AC
  2. Confirm Auth Token is the primary token, not a secondary one
  3. Re-enter credentials in Dashboard > Auth > Providers > Phone
  4. Save and wait 60 seconds for configuration to propagate

Error: SUPABASE_URL missing!

Cause: Environment variable not set or not loaded.

Solution:

  1. Check .env or .env.local file exists and contains the variable
  2. Restart your development server after adding env vars
  3. For frameworks, use the correct prefix: NEXT_PUBLIC_ (Next.js), EXPO_PUBLIC_ (Expo), REACT_APP_ (CRA), VUE_APP_ (Vue CLI)

Prevention: Use a .env.example file to document required variables.

Error: Row Level Security blocks all access

Cause: RLS is enabled but no policy grants access.

Solution:

  1. Check existing policies: select * from pg_policies where tablename = 'your_table';
  2. Add appropriate policies for SELECT, INSERT, UPDATE, DELETE
  3. Test with the SQL Editor using set role authenticated; or set role anon;

Prevention: Design and test RLS policies before enabling RLS on a table.

Caution

Disabling RLS (alter table your_table disable row level security;) exposes all rows to anyone with the anon key. Only disable for truly public, non-sensitive data.

Error: Foreign row save failures silently swallowed in Studio

Cause: Studio's SidePanelEditor does not surface errors from foreign key constraint violations (issue #44949).

Solution:

  1. Use the SQL Editor to run the INSERT/UPDATE directly and see the full error
  2. Verify the referenced foreign key value exists in the parent table
  3. Check the browser console Network tab for the underlying API error

Error: Project stuck on pausing or unpausing

Cause: Infrastructure provisioning delay (issue #45001).

Solution:

  1. Wait 30 minutes — most operations complete within this window
  2. If still stuck after 1 hour, contact Supabase support via the Dashboard
  3. Check the status page for ongoing incidents

Warning

Do not repeatedly trigger pause/unpause — each attempt queues a new operation and may extend the wait time.

Error: Connect modal stuck on loading for non-JS frameworks

Cause: Studio's connect modal only renders connection details for JavaScript-based frameworks (issues #44984, #44985).

Solution:

  1. Use the Settings > API page to get connection details directly
  2. Copy the project URL and API keys manually
  3. Use the generic REST API documentation for non-JS languages

Error: Can't save Email auth settings

Cause: Known issue with the auth settings form in Studio (issue #3192).

Solution:

  1. Clear browser cache and retry
  2. Try a different browser
  3. If persists, configure email auth via the Supabase CLI config instead

Error: invalid secret key after Postgres upgrade

Cause: PG 15 and PG 17 use different postgres UIDs. Starting a PG 17 container with a leftover db-config volume from PG 15 produces this error.

Solution:

  1. Run the upgrade script: docker/utils/upgrade-pg17.sh
  2. Or remove the old volume: docker volume rm supabase_db-config

Prevention: Follow the Postgres 17 upgrade guide before switching images.


7. FAQ

Q: What is Supabase?

Supabase is an open-source Firebase alternative that provides a Postgres database, authentication, real-time subscriptions, file storage, edge functions, and auto-generated APIs. You can use it as a hosted platform or self-host with Docker.

Q: Is Supabase free?

Supabase offers a free tier for hobby projects. Paid plans add more resources and features. Self-hosting is free — you provide the infrastructure.

Q: Can I use Supabase with frameworks other than React?

Yes. The JavaScript SDK (@supabase/supabase-js) works with any JavaScript framework. The repo's examples/ directory includes working implementations for Next.js, SvelteKit, Nuxt 3, Angular, Ionic (React, Angular, Vue), React Native (Expo), Flutter, Solid, Svelte, and more. The blocks/vue/ directory provides pre-built Vue/Nuxt UI blocks.

Q: How do I connect from a mobile app?

For React Native/Expo, use @supabase/supabase-js with EXPO_PUBLIC_SUPABASE_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY environment variables. For Flutter, use the supabase_flutter package (separate repository).

Q: What is the difference between the anon key and service role key?

The anon key is safe to use in client code — it respects Row Level Security policies. The service role key bypasses RLS entirely and should only be used server-side for admin operations.

Q: How do I run Supabase locally?

Use the Supabase CLI: npx supabase init then npx supabase start. This starts a local Postgres, GoTrue (auth), PostgREST, Realtime, Storage, Studio, and Inbucket (email testing) using Docker.

Q: Can I self-host Supabase?

Yes. The docker/ directory contains a production-ready Docker Compose setup with all services (Kong API gateway, GoTrue auth, PostgREST, Realtime, Storage, Studio, Postgres, and more). See the Admin Guide for deployment instructions.

Q: What Postgres version does Supabase use?

The default local development version is Postgres 15 (configured in supabase/config.toml under [db] major_version). A Postgres 17 override is available via docker/docker-compose.pg17.yml for self-hosted deployments.

Q: How do I expose additional schemas via the API?

Add them to the schemas array in supabase/config.toml under [api]. The default includes public, storage, and graphql_public. After changing, restart the local stack or update the remote project's PostgREST configuration.

Q: Why are my Realtime subscriptions not working?

Three common causes: (1) The table is not in the supabase_realtime publication — run alter publication supabase_realtime add table your_table;, (2) RLS policies block SELECT for the subscribing user's role, (3) the WebSocket connection is blocked by a proxy or firewall.

Q: How do I use Supabase with Vue/Nuxt?

The blocks/vue/ directory provides pre-built Nuxt UI blocks including password-based auth, social auth, realtime cursor tracking, avatar stacks, and file dropzones. These blocks include server middleware for Supabase SSR auth.

Q: How do I handle file uploads with size validation?

Set the file_size_limit in supabase/config.toml under [storage]. The default is 50MiB. Client-side, check the file size before uploading and handle the 413 error if the server rejects the file.

Q: What is Supabase Studio?

Studio is the web-based dashboard for managing Supabase projects. It includes a Table Editor, SQL Editor, Auth management, Storage browser, Edge Function logs, and database schema visualization. It runs as a Next.js application.