
מה זה
Supabase היא backend-as-a-service בקוד פתוח שנבנה על Postgres. לכנות אותה "Firebase פתוחה" זו הערכת חסר - מתחת למכסה מדובר בסטק מכוּוָן של הכלים הטובים ביותר ל-Postgres: PostgREST ליצירת REST APIs אוטומטית, GoTrue ל-JWT auth, Realtime (Elixir) להאזנה חיה לשינויי שורות דרך WebSockets, Storage API תואם S3 עם ACLs שמאכפת Postgres, Edge Functions (Deno) ללוגיקה serverless, ו-pgvector ל-embeddings. הכל תחת רישיון Apache-2.0, כך שאפשר לארח כל חלק ממנו בעצמך.
הצעת הערך מאתגרת את שאר שוק ה-BaaS: מקבלים מסד נתונים Postgres אמיתי שנמצא בבעלותך (לא מאגר key-value קנייני), עם מדיניות Row Level Security שאפשר לבדוק, בנוסף ל-APIs אוטומטיים, auth, אחסון קבצים ופרימיטיבים של AI - כולם מדברים SQL מתחת. אפשר לעבור ל-Postgres נקי בכל רגע; שום דבר לא נועל אותך.
ארכיטקטורה
כל פרויקט Supabase הוא אוסף מכוּוָן של קונטיינרים סביב מופע Postgres יחיד:
- Postgres - מסד הנתונים הראשי; גרסאות Postgres יציבות ועדכניות עם extensions מותקנות מראש (pgvector, pg_graphql, pg_cron, pgsodium, postgis ועוד).
- PostgREST - קורא את סכמת Postgres וחושף כל טבלה כ-REST endpoint בנתיב
/rest/v1/<table>. - GoTrue - הרשמה/התחברות, אימייל + OAuth + magic link; מנפיק JWTs עם claim בשם
subשמכיל את ה-UUID של המשתמש. - Realtime - מתחבר לשכפול הלוגי של Postgres ומשדר אירועי INSERT/UPDATE/DELETE ללקוחות דרך WebSockets.
- Storage API - מאגר אובייקטים תואם S3; מדיניות bucket מאוכפת על ידי Postgres RLS.
- Edge Functions - סביבת ריצה Deno, פרוסה גלובלית על ה-edge.
- Kong - API gateway בחזית הכל.
לקוח ה-supabase-js עוטף את הכל. לקוח אחד, הקשר auth אחד, כל השירותים.
התקנה
שני דברים שכדאי להתקין - ה-CLI לפיתוח מקומי ומיגרציות, וה-JS SDK לקוד האפליקציה.
Supabase CLI:
# macOS (Homebrew tap)
brew install supabase/tap/supabase
# Node (project-local dev dep)
npm install supabase --save-dev
# Yarn / pnpm
yarn add supabase --dev
pnpm add supabase --save-dev --allow-build=supabase
# Scoop on Windows
scoop bucket add supabase https://github.com/supabase/scoop-bucket.git
scoop install supabase
אתחול פרויקט:
npx supabase init # creates supabase/ folder with config.toml, migrations/
npx supabase start # spins up Postgres + Studio + GoTrue + Realtime + Storage on Docker
npx supabase status # prints API URL, anon key, service_role key, JWT secret
לקוח JS:
npm install @supabase/supabase-js
הגדרות
הגדרות הפרויקט נמצאות ב-supabase/config.toml (נוצר על ידי supabase init). הערכים שנוגעים בהם בדרך כלל:
project_id = "my-app"
[api]
port = 54321
schemas = ["public", "graphql_public"]
max_rows = 1000
[db]
port = 54322
major_version = 15
[auth]
enabled = true
site_url = "http://localhost:3000"
additional_redirect_urls = ["https://my-app.vercel.app"]
jwt_expiry = 3600
[auth.email]
enable_signup = true
double_confirm_changes = true
[storage]
enabled = true
file_size_limit = "50MiB"
[edge_runtime]
enabled = true
policy = "oneshot"
פרטי גישה לסביבת ייצור - במשתני סביבה בלבד, לעולם לא ב-repo:
SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_ANON_KEY=eyJ… # safe to ship to client
SUPABASE_SERVICE_ROLE_KEY=eyJ… # server-side ONLY, bypasses RLS
דוגמאות קוד
Row Level Security - המושג החשוב ביותר ב-Supabase, שכן ה-anon key נשלח ללקוח וכל מי שמחזיק בו יכול לפנות ל-API. ה-RLS הוא שכבת ההרשאות האמיתית. טבלה שנוצרת דרך ה-Table Editor בדשבורד מגיעה עם RLS מופעל כברירת מחדל, אך טבלה שנוצרת ב-SQL גולמי - לא; חובה להפעיל אותו ידנית לכל טבלה ולכתוב את המדיניות ב-SQL. כל בקשה ממופה לאחד משני תפקידי Postgres: anon (לא מחובר) או authenticated (מחובר), וה-to במדיניות מצמצם אותה לתפקיד הרלוונטי.
-- 1. Create the table
create table profiles (
id uuid primary key,
user_id uuid references auth.users,
avatar_url text,
bio text
);
-- 2. Turn RLS on
alter table profiles enable row level security;
-- 3. SELECT: users see only their own row
create policy "Users can see their own profile."
on profiles for select
using ( (select auth.uid()) = user_id );
-- 4. INSERT: users can create only their own row
create policy "Users can create a profile."
on profiles for insert
to authenticated
with check ( (select auth.uid()) = user_id );
-- 5. UPDATE: users can update only their own row
create policy "Users can update their own profile."
on profiles for update
to authenticated
using ( (select auth.uid()) = user_id )
with check ( (select auth.uid()) = user_id );
שימו לב לעטיפה (select auth.uid()) במקום auth.uid() חשוף. זו לא קוסמטיקה: העטיפה ב-select גורמת ל-planner של Postgres להריץ initPlan ולחשב את התוצאה פעם אחת לכל statement במקום פעם לכל שורה. התיעוד הרשמי מדגים שאילתה שירדה מ-179ms ל-9ms (כ-95% שיפור) על טבלה גדולה רק בזכות העטיפה הזו - זו אחת הטעויות הכי שכיחות ב-RLS שמייצרת תוכניות שאילתה איטיות.
לקוח supabase-js - auth + query + realtime במקום אחד:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
email: 'me@example.com',
password: 'hunter2'
})
// Query (RLS automatically scopes to the logged-in user)
const { data: profile } = await supabase
.from('profiles')
.select('id, bio, avatar_url')
.single()
// Live subscription — fires on every INSERT/UPDATE/DELETE
const channel = supabase
.channel('profile-changes')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'profiles' },
(payload) => console.log('change:', payload))
.subscribe()
Edge Function (Deno, פרוסה על ה-edge):
# Scaffold
supabase functions new hello-world
# Writes supabase/functions/hello-world/index.ts
# index.ts — uses the built-in Deno.serve (no deno.land/std import needed)
Deno.serve(async (req) => {
const { name } = await req.json()
return Response.json({ message: `Hello ${name}!` })
})
# Serve locally
supabase functions serve hello-world
# Deploy globally
supabase functions deploy hello-world
pgvector - פרימיטיב AI/RAG מובנה:
-- Enable the extension
create extension if not exists vector;
-- 1536 dimensions = OpenAI text-embedding-3-small output
create table documents (
id bigserial primary key,
content text,
embedding vector(1536)
);
-- ANN index for fast similarity search
create index on documents
using hnsw (embedding vector_cosine_ops);
-- Top-5 nearest neighbours
select id, content
from documents
order by embedding <=> '[0.1, 0.2, …]'::vector
limit 5;
Auth
GoTrue מטפל בהרשמה, התחברות וניהול sessions. כל בקשה מאומתת נושאת JWT חתום בסוד המשותף של הפרויקט; ה-claim sub ב-JWT הוא ה-UUID של המשתמש, שמדיניות RLS קוראת דרך auth.uid(). לקוח supabase-js מרענן טוקנים בשקט ברקע ושומר את ה-session ב-local storage.
// Sign up — email + password
const { data, error } = await supabase.auth.signUp({
email: 'me@example.com',
password: 'hunter2',
})
// Magic link — no password, emailed sign-in
await supabase.auth.signInWithOtp({ email: 'me@example.com' })
// OAuth — redirects to provider, then back to site_url
await supabase.auth.signInWithOAuth({ provider: 'google' })
// Server-side: get the current user from a request
const { data: { user } } = await supabase.auth.getUser()
מה חדש / גרסה
Supabase מפרסמת "Developer Update" ציבורי מדי חודש (מתויג לפי שנה/חודש, למשל v1.26.05, ולא לפי מספר רץ) - נכון ליוני 2026, יוני 2026 הוא העדכון האחרון בזמן כתיבת שורות אלו. נושאים בולטים אחרונים בפלטפורמה:
- ספקי OAuth/OIDC מותאמים ושינויי חשיפת Data API.
- תקן ISO 27001 - הסמכה רשמית של הפלטפורמה.
- ה-SDK @supabase/server - חבילה ייעודית לצד השרת.
- Branching - מסד נתונים נפרד לכל pull request לצורך תצוגה מקדימה, במקביל ל-preview deploys בסגנון Vercel, כולל branching ללא Git.
למה זה חשוב בפועל
בשימוש יומיומי, Supabase מתאימה לרגע שבו פרויקט גדל מעבר לקובץ סטטי וטופס ומתחיל לדרוש מצב אמיתי - משתמשים, הרשאות, קבצים. לזרימות פשוטות של איסוף לידים או טבלה בודדת, פתרון קל יותר כמו worker עם מסד נתונים מינימלי לרוב מספיק ואף עדיף. אבל ברגע שצריך auth + RLS + storage על משטח אחד קוהרנטי, זה בדיוק המקום שבו פלטפורמה כזו חוסכת הרבה חיבור ידני. מניסיון, המנוף הגדול הוא ה-CLI: היכולת להרים את כל הסטק על Docker לפיתוח מקומי - כולל Studio, GoTrue, Realtime ו-Storage - מאפשרת לעבוד עם זרימות נתונים זהות לייצור גם ללא חיבור לאינטרנט, וזה משנה את קצב הפיתוח.
מה שמחזיר אליה שוב ושוב: זה פשוט Postgres. כל מדיניות RLS היא SQL שאפשר לבדוק, לנהל בגרסאות ולהריץ עליו מיגרציות. כל שאילתה היא SELECT רגיל. כשמשהו משתבש, התשובה נמצאת ב-pg_stat_statements - לא בכרטיס תמיכה אצל ספק. מיגרציות נשמרות כקבצי SQL פשוטים ב-supabase/migrations/ ומוחלות עם supabase db push; rollback הוא פשוט מיגרציה הפוכה. וביום שרוצים לעבור הלאה, מריצים pg_dump וממשיכים. ה-escape hatch הזה - העובדה שהמנוע הבסיסי הוא Postgres ללא שינוי - הוא מה שהופך את ה-lock-in לאפס.