1 min read
BackendSupabase: Die Open-Source Firebase Alternative für 2026
Supabase als vollständige Backend-Plattform. PostgreSQL, Realtime, Auth, Edge Functions und Vector Embeddings in einem Stack.
SupabasePostgreSQLRealtime DatabaseEdge FunctionsAuthenticationFirebase Alternative

Supabase: Die Open-Source Firebase Alternative für 2026
Meta-Description: Supabase als vollständige Backend-Plattform. PostgreSQL, Realtime, Auth, Edge Functions und Vector Embeddings in einem Stack.
Keywords: Supabase, PostgreSQL, Realtime Database, Edge Functions, Authentication, Firebase Alternative, Vector Embeddings
Einführung
Supabase ist die Open-Source Firebase Alternative, die auf PostgreSQL aufbaut. 2026 bietet es eine vollständige Backend-Plattform: Database, Auth, Realtime, Edge Functions, Storage und Vector Embeddings – alles integriert.
Supabase Stack
┌─────────────────────────────────────────────────────────────┐
│ SUPABASE PLATFORM │
├─────────────────────────────────────────────────────────────┤
│ │
│ Database Layer: │
│ ├── PostgreSQL (Enterprise-Grade) │
│ ├── Row Level Security (RLS) │
│ ├── PostgREST (Auto-Generated APIs) │
│ └── pgvector (Vector Embeddings) │
│ │
│ Realtime Layer: │
│ ├── Postgres Changes (CDC) │
│ ├── Broadcast (User-to-User) │
│ ├── Presence (Online Status) │
│ └── WebSocket Connections │
│ │
│ Auth Layer: │
│ ├── Email/Password │
│ ├── OAuth Providers (Google, GitHub, etc.) │
│ ├── Magic Links │
│ └── Phone/SMS Auth │
│ │
│ Edge Functions: │
│ ├── Deno Runtime │
│ ├── TypeScript/JavaScript │
│ └── Global Distribution │
│ │
│ Storage: │
│ ├── S3-Compatible │
│ ├── CDN Integration │
│ └── Image Transformations │
│ │
└─────────────────────────────────────────────────────────────┘Database Setup
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
import { Database } from './database.types';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey);
// Server-Side mit Service Role
import { createClient } from '@supabase/supabase-js';
export const supabaseAdmin = createClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
autoRefreshToken: false,
persistSession: false
}
}
);Schema Definition (SQL)
-- Users Tabelle (erweitert auth.users)
CREATE TABLE public.profiles (
id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY,
username TEXT UNIQUE,
full_name TEXT,
avatar_url TEXT,
bio TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Posts Tabelle
CREATE TABLE public.posts (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
author_id UUID REFERENCES public.profiles(id) ON DELETE CASCADE NOT NULL,
title TEXT NOT NULL,
content TEXT,
published BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Trigger für updated_at
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER profiles_updated_at
BEFORE UPDATE ON public.profiles
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
CREATE TRIGGER posts_updated_at
BEFORE UPDATE ON public.posts
FOR EACH ROW EXECUTE FUNCTION update_updated_at();Row Level Security (RLS)
-- RLS aktivieren
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
-- Profiles: Jeder kann lesen, nur Owner kann schreiben
CREATE POLICY "Profiles sind öffentlich lesbar"
ON public.profiles FOR SELECT
USING (true);
CREATE POLICY "User kann eigenes Profil bearbeiten"
ON public.profiles FOR UPDATE
USING (auth.uid() = id);
-- Posts: Veröffentlichte sind lesbar, Autor kann alles
CREATE POLICY "Veröffentlichte Posts sind lesbar"
ON public.posts FOR SELECT
USING (published = true OR auth.uid() = author_id);
CREATE POLICY "Autor kann eigene Posts erstellen"
ON public.posts FOR INSERT
WITH CHECK (auth.uid() = author_id);
CREATE POLICY "Autor kann eigene Posts bearbeiten"
ON public.posts FOR UPDATE
USING (auth.uid() = author_id);
CREATE POLICY "Autor kann eigene Posts löschen"
ON public.posts FOR DELETE
USING (auth.uid() = author_id);CRUD Operations
// CREATE
async function createPost(post: { title: string; content: string }) {
const { data, error } = await supabase
.from('posts')
.insert({
title: post.title,
content: post.content,
author_id: (await supabase.auth.getUser()).data.user?.id
})
.select()
.single();
if (error) throw error;
return data;
}
// READ
async function getPosts() {
const { data, error } = await supabase
.from('posts')
.select(`
*,
author:profiles(username, avatar_url)
`)
.eq('published', true)
.order('created_at', { ascending: false })
.limit(10);
if (error) throw error;
return data;
}
// READ mit Pagination
async function getPostsPaginated(page: number, pageSize: number = 10) {
const from = page * pageSize;
const to = from + pageSize - 1;
const { data, error, count } = await supabase
.from('posts')
.select('*, author:profiles(username)', { count: 'exact' })
.eq('published', true)
.range(from, to);
return { data, count, hasMore: count ? to < count - 1 : false };
}
// UPDATE
async function updatePost(id: string, updates: Partial<Post>) {
const { data, error } = await supabase
.from('posts')
.update(updates)
.eq('id', id)
.select()
.single();
if (error) throw error;
return data;
}
// DELETE
async function deletePost(id: string) {
const { error } = await supabase
.from('posts')
.delete()
.eq('id', id);
if (error) throw error;
}Realtime Subscriptions
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabase';
import { RealtimeChannel } from '@supabase/supabase-js';
// 1. Database Changes (CDC)
function useRealtimePosts() {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
// Initial Load
supabase.from('posts').select('*').then(({ data }) => {
if (data) setPosts(data);
});
// Subscribe to Changes
const channel = supabase
.channel('posts-changes')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'posts'
},
(payload) => {
if (payload.eventType === 'INSERT') {
setPosts(prev => [payload.new as Post, ...prev]);
} else if (payload.eventType === 'UPDATE') {
setPosts(prev =>
prev.map(p => p.id === payload.new.id ? payload.new as Post : p)
);
} else if (payload.eventType === 'DELETE') {
setPosts(prev => prev.filter(p => p.id !== payload.old.id));
}
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, []);
return posts;
}
// 2. Broadcast (User-to-User Messaging)
function useBroadcast(roomId: string) {
const [messages, setMessages] = useState<Message[]>([]);
useEffect(() => {
const channel = supabase.channel(`room:${roomId}`)
.on('broadcast', { event: 'message' }, ({ payload }) => {
setMessages(prev => [...prev, payload]);
})
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, [roomId]);
const sendMessage = (content: string) => {
supabase.channel(`room:${roomId}`).send({
type: 'broadcast',
event: 'message',
payload: { content, timestamp: new Date().toISOString() }
});
};
return { messages, sendMessage };
}
// 3. Presence (Online Status)
function usePresence(roomId: string, userId: string) {
const [onlineUsers, setOnlineUsers] = useState<string[]>([]);
useEffect(() => {
const channel = supabase.channel(`presence:${roomId}`)
.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState();
const users = Object.values(state).flat().map(p => p.user_id);
setOnlineUsers(users);
})
.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await channel.track({ user_id: userId });
}
});
return () => {
supabase.removeChannel(channel);
};
}, [roomId, userId]);
return onlineUsers;
}Authentication
// Sign Up
async function signUp(email: string, password: string) {
const { data, error } = await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${window.location.origin}/auth/callback`
}
});
return { data, error };
}
// Sign In
async function signIn(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password
});
return { data, error };
}
// OAuth Sign In
async function signInWithOAuth(provider: 'google' | 'github') {
const { data, error } = await supabase.auth.signInWithOAuth({
provider,
options: {
redirectTo: `${window.location.origin}/auth/callback`
}
});
return { data, error };
}
// Sign Out
async function signOut() {
const { error } = await supabase.auth.signOut();
return { error };
}
// Auth State Hook
function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
setLoading(false);
});
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setUser(session?.user ?? null);
}
);
return () => subscription.unsubscribe();
}, []);
return { user, loading };
}Edge Functions
// supabase/functions/send-email/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type'
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);
const { to, subject, body } = await req.json();
// Send email via Resend, SendGrid, etc.
const response = await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${Deno.env.get('RESEND_API_KEY')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'noreply@example.com',
to,
subject,
html: body
})
});
const result = await response.json();
return new Response(JSON.stringify(result), {
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
});
// Client-Side Aufruf
const { data, error } = await supabase.functions.invoke('send-email', {
body: {
to: 'user@example.com',
subject: 'Welcome!',
body: '<h1>Welcome to our platform!</h1>'
}
});Vector Embeddings (AI)
-- pgvector Extension aktivieren
CREATE EXTENSION IF NOT EXISTS vector;
-- Documents Tabelle mit Embeddings
CREATE TABLE documents (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
content TEXT NOT NULL,
embedding VECTOR(1536), -- OpenAI ada-002 Dimension
metadata JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Index für schnelle Similarity Search
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Similarity Search Funktion
CREATE OR REPLACE FUNCTION search_documents(
query_embedding VECTOR(1536),
match_count INT DEFAULT 5
)
RETURNS TABLE (
id UUID,
content TEXT,
similarity FLOAT
) AS $$
BEGIN
RETURN QUERY
SELECT
documents.id,
documents.content,
1 - (documents.embedding <=> query_embedding) AS similarity
FROM documents
ORDER BY documents.embedding <=> query_embedding
LIMIT match_count;
END;
$$ LANGUAGE plpgsql;// Embedding generieren und speichern
async function addDocument(content: string) {
// Embedding via OpenAI
const embeddingResponse = await openai.embeddings.create({
model: 'text-embedding-ada-002',
input: content
});
const embedding = embeddingResponse.data[0].embedding;
// In Supabase speichern
const { data, error } = await supabase
.from('documents')
.insert({ content, embedding })
.select()
.single();
return data;
}
// Similarity Search
async function searchDocuments(query: string) {
// Query Embedding
const embeddingResponse = await openai.embeddings.create({
model: 'text-embedding-ada-002',
input: query
});
const queryEmbedding = embeddingResponse.data[0].embedding;
// Search via RPC
const { data, error } = await supabase.rpc('search_documents', {
query_embedding: queryEmbedding,
match_count: 5
});
return data;
}Fazit
Supabase bietet 2026:
- PostgreSQL Power: Enterprise-DB mit RLS, Triggers, Functions
- Realtime Built-in: CDC, Broadcast, Presence über WebSockets
- Edge Functions: Deno-basiert, global verteilt
- Vector Search: pgvector für AI/RAG-Anwendungen
Eine vollständige Backend-Plattform für moderne Anwendungen.
Bildprompts
- "Database and real-time connections flowing together, Supabase architecture visualization"
- "PostgreSQL elephant with real-time lightning bolts, modern database concept"
- "Edge functions distributed globally on world map, serverless infrastructure"