Umów konsultację

Bezpłatna wycena w 24h

Supabase vs własny backend — kiedy co (i czy trzymać dane u dostawcy)

Supabase vs własny backend — kiedy co (i czy trzymać dane u dostawcy)

Narzędzia16 czerwca 20269 min czytania

Supabase to PostgreSQL + Auth + Storage + Realtime + Edge Functions w jednej platformie BaaS (Backend-as-a-Service). Open source, hostowany albo self-hosted. W ostatnich 2 latach stał się domyślnym wyborem dla startupów na Next.js — z dobrego powodu: skraca czas wdrożenia MVP z miesięcy do tygodni. Ale nie zawsze to dobry wybór. W tym wpisie rozpisujemy trade-offy, które bierzemy pod uwagę, gdy klient pyta: „Supabase czy własny backend?"

Co dokładnie daje Supabase

  • PostgreSQL — pełna relacyjna baza, taka jak na każdym własnym serwerze,
  • Row Level Security (RLS) — kontrola dostępu na poziomie wierszy w SQL, bez warstwy aplikacyjnej,
  • Authentication — JWT, OAuth (Google, GitHub, ~25 providers), magic links, OTP,
  • Storage — S3-kompatybilny obiekt storage do zdjęć, dokumentów, plików,
  • Realtime — subskrypcje WebSocket do zmian w bazie (czat, dashboardy live),
  • Edge Functions — Deno/TypeScript funkcje serverless,
  • Auto-generated REST API i GraphQL bezpośrednio z schema bazy.

Kiedy Supabase to dobry wybór

1. MVP startupu w 6-12 tygodni

Nie masz czasu pisać własnej autentykacji, schematu uprawnień i deployu bazy. Supabase + Next.js + Vercel daje cały stack w 1 wieczór konfiguracji.

2. Aplikacja SaaS B2B z prostą logiką

CRUD nad relacyjną bazą, autentykacja, role użytkowników, integracje przez Edge Functions. 80% backendu można zrobić w RLS bez ani jednego API endpointa.

3. Realtime jako requirement

Czat, kolaboracyjna edycja, dashboard live. Supabase Realtime działa out-of-the-box. Własne WebSocket od zera to 2-3 tygodnie pracy.

4. Mały zespół, brak DevOps

Brak osoby od bazy danych, backupów, monitoringu. Supabase to obsługuje za Ciebie.

Kiedy Supabase to zły wybór

1. Aplikacja z bardzo dużym ruchem na bazę

Supabase ma limity per plan (połączenia, requests, storage). Dla aplikacji z > 1M zapytań dziennie szybko zaczyna być droższe niż własny Postgres na DigitalOcean lub Hetznerze.

2. Skomplikowana logika biznesowa

RLS świetnie sprawdza się w 90% przypadków, ale dla logiki typu „użytkownik może edytować, jeśli ma rolę X i status zamówienia Y i nie minął termin Z" — Edge Functions stają się tańsze niż gimnastyka w SQL. Własny backend daje tu więcej kontroli.

3. Wymóg trzymania danych w PL / on-premise

Supabase hostowany jest na AWS (EU regions dostępne, ale dane fizycznie u Amazonu). Dla branż regulowanych (medyczna, finansowa, publiczna) self-hosted Supabase lub własny stack to często wymóg.

4. Vendor lock-in jako ryzyko

Supabase jest open source — teoretycznie możesz exportować i hostować sam. W praktyce migracja produkcyjnego Supabase do self-hosted to 1-2 tygodnie pracy i nieoczywiste pułapki (Edge Functions, Realtime config). Lepiej z góry zdecydować, czy to akceptowalne.

Koszty — kiedy Supabase jest droższy niż własny Postgres

Cennik (czerwiec 2026):

  • Free — 500 MB bazy, 1 GB storage, 50 000 monthly active users. Wystarczy dla MVP i małych projektów.
  • Pro ($25/mies.) — 8 GB bazy, 100 GB storage, 100 000 MAU. Sweet spot dla większości produkcyjnych aplikacji.
  • Team ($599/mies.) — dla zespołów z SLA, audit logs, multi-region.

Porównanie: własny PostgreSQL na Hetzner CCX13 (4 vCPU, 16 GB RAM) — ~25 €/mies. + DevOps + backupy. Dla aplikacji do średniej skali Supabase Pro jest cenowo opłacalny do około 1-2 mln zapytań dziennie. Wyżej — własny stack staje się tańszy.

Supabase + Next.js — sweet spot

Najlepiej Supabase wypada w połączeniu z Next.js App Router. Konkretny minimum setup:

// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export const supabase = () => {
  const cookieStore = cookies()
  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name) { return cookieStore.get(name)?.value },
        set(name, value, options) { cookieStore.set({ name, value, ...options }) },
        remove(name, options) { cookieStore.set({ name, value: '', ...options }) },
      },
    }
  )
}

// app/dashboard/page.tsx
export default async function Dashboard() {
  const db = supabase()
  const { data: orders } = await db.from('orders').select('*').limit(20)
  return <OrdersList orders={orders} />
}

Server components czytają bezpośrednio z Postgres bez warstwy API. Autentykacja przez middleware Next.js, Storage do obrazów z next/image, Edge Functions (Deno/TypeScript) dla webhooków Stripe, Resend, PayU.

To stack, w którym 80% backendu robisz w bazie (RLS + funkcje SQL), 20% w Edge Functions. Next.js to tylko frontend i orkiestracja. Dla MVP startupu od pomysłu do produkcji to często tygodnie zamiast miesięcy.

Max Mazurkiewicz

Max Mazurkiewicz

Founder

POTRZEBUJESZ SPERSONALIZOWANEJ WYCENY?

Chcesz się na coś zdecydować ale od nadmiaru możliwości boli głowa? Skontaktuj się z nami, dobierzemy rozwiązanie do potrzeb Twojej firmy.

Umów się na konsultację

Row Level Security — przykład, który warto skopiować

RLS jest mocną funkcją, ale wymaga uwagi. Klasyczne policy „użytkownik widzi tylko swoje zamówienia":

-- Włącz RLS na tabeli
alter table orders enable row level security;

-- Policy: użytkownik widzi tylko swoje zamówienia
create policy "Users can view their own orders"
on orders for select
using (auth.uid() = user_id);

-- Policy: admin widzi wszystkie zamówienia
create policy "Admins can view all orders"
on orders for select
using (
  exists (
    select 1 from user_roles
    where user_id = auth.uid() and role = 'admin'
  )
);

Trzy pułapki, które łapiemy w code review przy RLS:

  • Brak enable row level security — policy są zdefiniowane, ale nie egzekwowane. Dane wyciekają.
  • Policy z permissive default — np. brak osobnej policy dla INSERT, więc każdy zalogowany może wstawiać do tabeli (mimo SELECT ograniczonego do swoich).
  • Service role klucz w kodzie frontend — service role omija RLS. Klucz musi siedzieć tylko w server components / Edge Functions, nigdy w client components.

Kiedy wybraliśmy Neon zamiast Supabase — Giełda Biomasy

W projekcie Giełdy Biomasy świadomie wybraliśmy Neon Postgres (czysty serverless Postgres) zamiast Supabase. Powody:

  • Monorepo z 4 aplikacjami dzielącymi tę samą bazę — Supabase's auth + Storage były dla nas zbędne, bo i tak budowaliśmy własną warstwę domenową (rejestracja firm z weryfikacją NIP/REGON/VAT, której Supabase Auth nie obsługuje natywnie).
  • Logika biznesowa zbyt złożona dla RLS — uprawnienia w Giełdzie zależą od wielu reguł (rola, status weryfikacji, typ subskrypcji, kategoria oferty). Edge Functions byłyby bardziej czytelne niż gigantyczna policy SQL.
  • Compliance pod rozporządzenie Min. Klimatu z 2025 — wymagało własnej warstwy walidacji parametrów pelletu, której nie chcieliśmy mieszać z generycznym RLS.
  • PayU REST API — krajowy operator, w którym implementacja webhooku IPN wymaga walidacji podpisu MD5 sender check w stałym czasie. Wygodniej w Route Handler Next.js niż w Edge Function Supabase.

Auth zrobiliśmy ręcznie z Google OAuth + sesje JWT szyfrowane kryptograficznie. Storage to S3-compatible (Cloudflare R2). Łącznie więcej kodu niż w Supabase, ale pełna kontrola — i koszt skali liniowy względem ruchu, nie skokowy między planami BaaS.

Drobne pułapki Supabase, które warto znać

Trzy rzeczy, na które łapaliśmy się w realnych projektach:

  • Connection pooling — domyślny pool Supabase działa w trybie transaction (PgBouncer). To znaczy, że prepared statements i zaawansowane typy Postgres mogą się zachowywać inaczej niż w bezpośrednim połączeniu. Dla Next.js z Vercel zwykle OK, ale dla aplikacji z długimi sesjami i procedurami składowanymi trzeba podpiąć pool w trybie session (osobny port).
  • Cold start Edge Functions — pierwszy request po dłuższej przerwie ma latencję 500-1500 ms (Deno runtime się rozgrzewa). Dla webhooków zewnętrznych (Stripe, PayU) to OK, dla user-facing zapytań nieakceptowalne.
  • Realtime nie skaluje liniowo — przy > 1000 jednoczesnych subskrybentów na ten sam channel wydajność spada. Dla wieloosobowych dashboardów warto rozważyć dedykowany WebSocket server (Soketi, Pusher) zamiast Supabase Realtime.

Wnioski

Supabase to narzędzie produktywności, które ma świetny moment użycia: od MVP do średniego scale-up. Powyżej skali (i poniżej oczekiwanej elastyczności logiki biznesowej) własny backend z Postgres na Neonie lub własnym serwerze daje większą kontrolę za niższą cenę. Sprawdzonym wzorem jest też: zaczynamy od Supabase, eksportujemy do self-hosted, gdy skala uzasadnia — ale wtedy ważne, żeby od pierwszego dnia nie wpadać w features, których nie można łatwo odtworzyć (np. Realtime z subskrypcjami WebSocket, które trzeba by potem przepisać na własny WebSocket server).

Pełna oferta budowy aplikacji webowych: aplikacje webowe. Strony Next.js: strony Next.js. Pellet biomasy — case study, w którym świadomie użyliśmy własnego Postgres na Neonie zamiast Supabase: Giełda Biomasy.

Najczęściej zadawane pytania

Tak — Supabase jest używany przez tysiące firm produkcyjnie, w tym polskie startupy z setkami tysięcy użytkowników. Dla średniej skali to świetne narzędzie. Powyżej skali (kilka milionów zapytań dziennie) trzeba kalkulować koszt vs własny Postgres na dedykowanym serwerze.

RLS to kontrola dostępu do danych na poziomie wierszy w bazie. Piszesz SQL policy: „użytkownik widzi tylko swoje zamówienia" → baza sama egzekwuje to przy każdym zapytaniu, niezależnie od kodu aplikacji. To eliminuje warstwy autoryzacji w API. Mocna funkcja — ale trudna do nauczenia. Złe RLS = wyciek danych.

Tak — Supabase to PostgreSQL pod spodem. Eksport bazy danych = standardowy pg_dump. Trudniejsze są funkcje Supabase: Auth, Storage, Realtime, Edge Functions — te trzeba odtworzyć w nowej infrastrukturze. Migracja jest realna, ale to 1-2 tygodnie pracy. Lepiej decyzję podjąć od początku świadomie.

Neon to czysty serverless Postgres bez warstwy BaaS — auth, storage i realtime musisz zrobić sam. Jest lepszy wybór, gdy: (a) potrzebujesz bardziej elastycznej logiki niż RLS, (b) chcesz mniej vendor lock-in, (c) masz zespół z doświadczeniem backendowym. W Giełdzie Biomasy wybraliśmy Neon zamiast Supabase właśnie z tych powodów — i napisaliśmy Auth/Storage sami.

Max Mazurkiewicz
Max Mazurkiewicz
Founder
Digital marketing expert