arielshemesh1999@gmail.com · ישראל
← כל המאמרים

Supabase

פלטפורמת פיתוח Postgres בקוד פתוח (Apache-2.0) - מסד נתונים, auth, storage, realtime, edge functions ו-vector embeddings, כולם מחוברים לדשבורד אחד ולקוח JS יחיד עם טיפוסים סטטיים.

מה זה

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 לאפס.

מקורות