Supabase SDK Compatibility
Which Supabase client SDK features instancez supports.
instancez implements the Supabase wire protocol. Any official Supabase SDK works against it — with the gaps noted below.
supabase-js feature matrix
Section titled “supabase-js feature matrix”| Feature | Status | Notes |
|---|---|---|
Database — supabase.from() |
✅ Full | select, insert, update, upsert, delete. All PostgREST filter operators (eq, neq, gt, gte, lt, lte, like, ilike, is, in, contains, containedBy, overlaps, …). Embeds (!inner, !left, FK hints, many-to-many through junction tables, 300 PGRST201 when ambiguous). order, limit, offset, Range-header pagination with PostgREST’s statuses: 206 for a partial counted page, 416 PGRST103 past the end (data and count are null). Prefer: return, count, resolution, missing, max-affected, tx. .single() on insert, upsert, update and delete returns 406 PGRST116 and rolls back unless exactly one row is affected. Row values serialized like PostgREST (to_json), see Value formats. CSV responses (Accept: text/csv). HEAD requests. The secret key can use .explain() (text or JSON, with analyze, verbose, settings, buffers, wal) on reads. The plan runs in a transaction that is always rolled back. Other callers get 406 PGRST107. .explain() on insert, upsert, update, delete and rpc returns 406 PGRST107 for every caller, the secret key included, and nothing runs. |
Auth — supabase.auth.* |
✅ Full | Email + password, magic link / OTP, anonymous sign-in, session refresh, updateUser, resetPasswordForEmail, identity linking/unlinking (linkIdentity needs the frontend on the API’s origin, see Auth), PKCE. |
OAuth — signInWithOAuth |
⚠️ Google, GitHub and Apple only | The provider field accepts google, github and apple. Other providers return a 400. Apple is configured in YAML only. |
OAuth — signInWithIdToken |
⚠️ Google and Apple only | Reads id_token like GoTrue (token also works). Verifies the token against the provider’s keys, with nonce (a token that has one needs one in the request, and the reverse). Google compares it raw. Apple compares the claim to the hex SHA-256 of the request nonce. Apple takes several audiences in client_id (comma-separated) for iOS bundle IDs. |
Auth Admin — supabase.auth.admin.* |
✅ Full | createUser, listUsers (paginated), getUserById, updateUserById, deleteUser, inviteUserByEmail, generateLink, signOut (user), deleteFactor. |
MFA — supabase.auth.mfa.* |
⚠️ TOTP only | enroll, challenge, verify, challengeAndVerify, unenroll, listFactors and getAuthenticatorAssuranceLevel all work for TOTP, with Supabase’s aal/amr JWT claims. Phone/SMS factors are not supported. |
Storage — supabase.storage.* |
✅ Full | RLS expressions can use storage.foldername(), storage.filename(), storage.extension() and the owner / owner_id columns. Upload (with metadata), download, move, copy, remove (batch and DELETE /object/<bucket>/<path>, 403 when RLS denies, 404 when missing), list, listV2, info, exists. Guest (publishable-key) calls run as anon under the bucket’s rls:, as in Supabase. Public URLs. Signed URLs (download, with the download or transform option, and upload). /render/image/{public,authenticated,sign} serve transform URLs. Bucket management (create, update, delete, empty). Image transforms: resize (cover, contain, fill), quality, format (jpeg, png); WebP and AVIF output are not supported. Transform limits match Supabase: 1-2500px, 25MB and 50MP sources. |
Edge Functions — supabase.functions.invoke() |
✅ Full | Calls code functions at /functions/v1/<name>. |
RPC — supabase.rpc() |
✅ Full | Calls SQL functions declared under rpc: in instancez.yaml. setof results take filters, embeds and aggregates like tables. |
Type generation — supabase gen types |
⚠️ TypeScript only, differences listed | inz gen types writes a Database type and Constants for createClient<Database>() from the yaml, with no database needed. See TypeScript types. |
Realtime — supabase.channel() |
❌ Not supported yet | instancez has no pub/sub listener. For event-driven patterns in the meantime, use a code function with Postgres LISTEN/NOTIFY or a webhook receiver. |
Auth behavior differences from GoTrue
Section titled “Auth behavior differences from GoTrue”instancez’s auth server matches Supabase’s GoTrue on the wire, with a few deliberate differences:
- A banned user gets 403
user_bannedon every path, including the password grant. GoTrue returns 400 there and 403 elsewhere. - A TOTP code is rejected if its 30-second step was already used on that factor, even within the normal replay window GoTrue allows.
- Linking an OAuth identity to an account that has a password but isn’t verified is refused (422
email_exists). GoTrue strips the password and links instead; on an instance withverify_email: false, every password user is unverified, so GoTrue’s behavior would silently drop their password. /otpwithallow_signup: falsereturns an empty 200 for an unknown address, not GoTrue’s 422, so the response never reveals whether the account exists.- With
allow_signup: false,/signupand first-timesignInWithIdTokenreturn 422signup_disabled(the browser OAuth callback redirects withunexpected_failure), and anonymous sign-in off returns 422anonymous_provider_disabledwhen signup is allowed, as in GoTrue. Earlier releases returned 403. /otpand/recoverreturn a silent empty 200 on a repeat within 60 seconds, so neither reveals whether the account exists./resendinstead returns 429over_email_send_rate_limiton the same cooldown — matching GoTrue, but inconsistent with instancez’s own/otpand/recover.- An access token issued before a ban or a password change stays valid until it expires; it isn’t revoked early.
- JWTs are only accepted if signed
RS256orHS256.
REST behavior differences from PostgREST
Section titled “REST behavior differences from PostgREST”- CSV cells differ from PostgREST’s CSV; see CSV output.
rpcignoresAccept: text/csv. - Rows from
Accept: text/csv,application/geo+jsonand RPC calls withcount=exactlist keys in alphabetical order, not select order.
Direct storage upload (no SDK needed)
Section titled “Direct storage upload (no SDK needed)”When using the S3 provider, you can bypass the SDK entirely and upload files straight to S3 via a presigned URL — useful in serverless environments where routing bytes through the server is expensive:
// Get a presigned upload URLconst { id, upload_url } = await fetch('/storage/avatars/sign', { method: 'POST', headers: { Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ content_type: file.type, size: file.size, path: `${userId}/${file.name}` }), // path is optional}).then(r => r.json())
// Upload directly to S3 — instancez is not in this pathawait fetch(upload_url, { method: 'PUT', headers: { 'Content-Type': file.type }, body: file })Uploads through supabase.storage.upload() are proxied and capped at about 4.5MB on Instancez Cloud. This direct flow is the way past that cap. See Storage for the full spec.
The integration test suite runs @supabase/supabase-js against a live instancez instance on every commit. If you find a gap, open an issue.