Supabase

Lightweight, dependency-free Supabase emulator covering the Auth (GoTrue) and REST (PostgREST) surfaces over HTTP/JSON.

KeyValue
Port54321
ProtocolREST API (HTTP + JSON)
Sizesmall

Default Connection

http://parlel-bridge:54321
SurfaceBase path
Auth (GoTrue)/auth/v1/
REST (PostgREST)/rest/v1/

Supported Operations

Auth (/auth/v1)

OperationNotes
Sign up / create userRegisters a user in the in-memory user map
Token / sessionReturns a session for a registered user

REST (/rest/v1/{table})

OperationRequest
Insert rowPOST /rest/v1/{table}
Select rowsGET /rest/v1/{table}
Update rowPATCH /rest/v1/{table}
Delete rowDELETE /rest/v1/{table}

Usage

The parlel/bridge sidecar exposes Supabase at http://parlel-bridge:54321, carrying the REST (HTTP/JSON) protocol over the sandbox HTTPS preview proxy. Your app connects with an unmodified @supabase/supabase-js client (or raw REST) — no Parlel code in the app.

# docker-compose.test.yml
include:
  - path: parlel-bridge.yml          # image: parlel/bridge
services:
  app:
    build: .
    env_file: test.env
    depends_on:
      parlel-bridge: { condition: service_healthy }
PARLEL_API_KEY=pk_... docker compose -f docker-compose.test.yml up
import { createClient } from "@supabase/supabase-js";

// Unmodified real client, pointed at the bridge hostname
// (or `localhost` if you run the bridge outside Docker and publish ports)
const supabase = createClient("http://parlel-bridge:54321", "parlel-anon-key");

await supabase.from("todos").insert({ title: "Ship it" });
const { data } = await supabase.from("todos").select("*");

Auth (GoTrue)

The Auth surface speaks the Supabase GoTrue wire protocol under /auth/v1/, so @supabase/supabase-js's supabase.auth.* methods work against the fake. State is in-memory and ephemeral; access tokens are JWT-shaped (header.payload.signature) strings generated deterministically (not cryptographically verifiable).

OperationRequestResponse
Sign upPOST /auth/v1/signup { email, password }{ access_token, refresh_token, token_type:"bearer", expires_in, expires_at, user }
Sign in (password)POST /auth/v1/token?grant_type=password { email, password }{ access_token, refresh_token, token_type:"bearer", expires_in, user }
Refresh sessionPOST /auth/v1/token?grant_type=refresh_token { refresh_token }new session { access_token, refresh_token, user }
Get userGET /auth/v1/user (Authorization: Bearer <access_token>)the GoTrue user object
Sign outPOST /auth/v1/logout (Authorization: Bearer <access_token>)204 No Content (session revoked)

The user object follows the GoTrue shape: { id, aud:"authenticated", role:"authenticated", email, email_confirmed_at, app_metadata, user_metadata, created_at, updated_at, … }.

Error shapes mirror GoTrue: invalid credentials return 400 { error:"invalid_grant", error_description:"Invalid login credentials" }, missing email on signup returns 422, and an invalid/missing bearer on GET /auth/v1/user returns 401 { code:401, error_code:"bad_jwt", msg }.

import { createClient } from "@supabase/supabase-js";
const supabase = createClient("http://parlel-bridge:54321", "parlel-anon-key");

const { data } = await supabase.auth.signUp({ email: "su@parlel.dev", password: "Secret1!" });
await supabase.auth.signInWithPassword({ email: "su@parlel.dev", password: "Secret1!" });
const { data: { user } } = await supabase.auth.getUser();
await supabase.auth.signOut();

Access via Parlel Sandbox

Supabase is an HTTP service, so the parlel/bridge sidecar exposes it at parlel-bridge:54321, carrying HTTP over the sandbox HTTPS preview proxy. Point your unmodified client or REST calls at that hostname (or localhost if you run the bridge outside Docker and publish ports).

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
Auth sign-up + password sign-in + sessionSupported
Auth refresh-token exchangeSupported
Auth GET /auth/v1/user (Bearer) + logoutSupported
REST insert / select / update / deleteSupported
Real JWT signing / verification (RS256/JWKS)Tokens are JWT-shaped, not verifiable
OAuth / magic links / OTP / email deliveryNot delivered
PostgREST filters / RLS / realtimeNot evaluated
Storage / edge functionsNot supported
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

SUPABASE_URL=http://parlel-bridge:54321
SUPABASE_ANON_KEY=parlel-anon-key
SUPABASE_SERVICE_ROLE_KEY=parlel-service-role-key
<!-- parlel:testenv:end -->