← Zurück zum Blog
Supabase hat sich 2026 als die führende Open-Source-Alternative zu Firebase etabliert. Was einst nur ein Postgres-Wrapper war, ist heute ein vollständiges Backend-Ökosystem: Authentication, Echtzeit-Datenbank, Object Storage, Serverless Edge Functions, Row Level Security und — besonders spannend für KI-Anwendungen — native pgvector-Unterstützung für Embedding-Suche.
Mit Claude Code lässt sich ein Supabase-Backend in Minuten aufsetzen und vollständig konfigurieren. Dieser Guide zeigt dir die wichtigsten Patterns von der Initialisierung bis zur Hybrid-Suche mit AI.
🔐
Authentication
OAuth, Magic Link, OTP, SSO
🐘
PostgreSQL
Vollständiges SQL, Extensions
⚡
Realtime
WebSockets, Broadcast, Presence
📦
Storage
S3-kompatibel, CDN-ready
🌐
Edge Functions
Deno, global deployed
🤖
pgvector
AI Embeddings, Hybrid Search
1. Supabase Setup: Client, SSR & TypeScript Types
Der erste Schritt ist die Installation der Supabase-Pakete. Für Server-Side-Rendering (Next.js, SvelteKit, Remix) nutzt du @supabase/ssr, für reine Client-Apps reicht @supabase/supabase-js.
bash — Installation
# Basis-Paket
npm install @supabase/supabase-js
# Mit SSR-Unterstützung (Next.js / SvelteKit)
npm install @supabase/supabase-js @supabase/ssr
# Supabase CLI für lokale Entwicklung & Migrations
npm install -D supabase
Environment Variables
Lege die Supabase-Credentials in deine .env.local. Die Werte findest du im Supabase Dashboard unter Project Settings → API.
.env.local
NEXT_PUBLIC_SUPABASE_URL=https://xyzabcdef.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Service Role Key: NUR server-seitig, niemals im Client!
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
⚠️ Sicherheit: Der SUPABASE_SERVICE_ROLE_KEY umgeht Row Level Security vollständig. Verwende ihn ausschließlich server-seitig (API Routes, Server Actions, Edge Functions) — niemals im Browser!
Client-Side Supabase Client
lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'
import type { Database } from '@/types/supabase'
export function createClient() {
return createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
Server-Side Client (Next.js App Router)
lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
import type { Database } from '@/types/supabase'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
},
},
}
)
}
TypeScript Database Types generieren
Claude Code kann automatisch typisierte Interfaces aus deinem Supabase-Schema generieren. Das gibt dir vollständige Autovervollständigung für alle Tabellen, Views und RPC-Funktionen:
bash — Types generieren
# Einmalig einrichten
npx supabase login
npx supabase link --project-ref xyzabcdef
# Types generieren (in types/supabase.ts)
npx supabase gen types typescript --linked > types/supabase.ts
# Oder direkt via API ohne CLI
npx supabase gen types typescript \
--project-id xyzabcdef \
--schema public > types/supabase.ts
Tipp
Füge den Codegen-Befehl als npm run types in deine package.json ein und führe ihn nach jeder Migration aus. Claude Code kann diesen Schritt automatisch in deine CI/CD-Pipeline integrieren.
2. Authentication: OAuth, Magic Links & SSR Sessions
Auth
Supabase Auth unterstützt E-Mail/Passwort, Magic Links, OTP per SMS, OAuth (Google, GitHub, Twitter, Discord, u.v.m.) sowie SAML SSO für Enterprise-Kunden. Die gesamte Session-Verwaltung läuft über JWTs, die automatisch refresht werden.
E-Mail-Registrierung und Login
lib/auth/actions.ts (Server Action)
'use server'
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
export async function signUp(formData: FormData) {
const supabase = await createClient()
const { error } = await supabase.auth.signUp({
email: formData.get('email') as string,
password: formData.get('password') as string,
options: {
emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
data: {
full_name: formData.get('name') as string,
}
}
})
if (error) throw error
redirect('/auth/check-email')
}
export async function signIn(formData: FormData) {
const supabase = await createClient()
const { error } = await supabase.auth.signInWithPassword({
email: formData.get('email') as string,
password: formData.get('password') as string,
})
if (error) throw error
redirect('/dashboard')
}
OAuth-Login (Google, GitHub, Discord)
components/OAuthButtons.tsx
'use client'
import { createClient } from '@/lib/supabase/client'
export function OAuthButtons() {
const supabase = createClient()
const signInWithGoogle = async () => {
await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
queryParams: {
access_type: 'offline',
prompt: 'consent',
}
}
})
}
const signInWithGitHub = async () => {
await supabase.auth.signInWithOAuth({
provider: 'github',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
scopes: 'read:user user:email'
}
})
}
return (
<div className="oauth-buttons">
<button onClick={signInWithGoogle}>Mit Google anmelden</button>
<button onClick={signInWithGitHub}>Mit GitHub anmelden</button>
</div>
)
}
Auth State Changes abonnieren
hooks/useAuth.ts
import { useEffect, useState } from 'react'
import { createClient } from '@/lib/supabase/client'
import type { User } from '@supabase/supabase-js'
export function useAuth() {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
const supabase = createClient()
useEffect(() => {
// Aktuelle Session holen
supabase.auth.getUser().then(({ data: { user } }) => {
setUser(user)
setLoading(false)
})
// Auth-Änderungen in Echtzeit abonnieren
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user ?? null)
setLoading(false)
}
)
return () => subscription.unsubscribe()
}, [])
return { user, loading }
}
Auth Callback Route (SSR Session)
app/auth/callback/route.ts
import { NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}${next}`)
}
}
return NextResponse.redirect(`${origin}/auth/error`)
}
ℹ️ Middleware für geschützte Routen: Ergänze eine middleware.ts im Root deines Projekts, die bei jeder Request die Session refresht und nicht authentifizierte User auf die Login-Seite weiterleitet.
3. Database & Row Level Security
Das Supabase-SDK bietet eine typisierte Query-Builder-API, die direkt auf PostgreSQL aufsetzt. RLS (Row Level Security) sorgt dafür, dass User nur auf ihre eigenen Daten zugreifen können — ohne zusätzlichen Server-Code.
CRUD-Operationen
lib/data/posts.ts
import { createClient } from '@/lib/supabase/server'
import type { Database } from '@/types/supabase'
type Post = Database['public']['Tables']['posts']['Row']
type PostInsert = Database['public']['Tables']['posts']['Insert']
// SELECT mit Filter
export async function getPostsByUser(userId: string): Promise<Post[]> {
const supabase = await createClient()
const { data, error } = await supabase
.from('posts')
.select('id, title, content, created_at, tags')
.eq('user_id', userId)
.order('created_at', { ascending: false })
.limit(20)
if (error) throw error
return data
}
// INSERT
export async function createPost(post: PostInsert): Promise<Post> {
const supabase = await createClient()
const { data, error } = await supabase
.from('posts')
.insert(post)
.select()
.single()
if (error) throw error
return data
}
// UPDATE
export async function updatePost(id: string, updates: Partial<PostInsert>): Promise<Post> {
const supabase = await createClient()
const { data, error } = await supabase
.from('posts')
.update({ ...updates, updated_at: new Date().toISOString() })
.eq('id', id)
.select()
.single()
if (error) throw error
return data
}
// DELETE
export async function deletePost(id: string): Promise<void> {
const supabase = await createClient()
const { error } = await supabase
.from('posts')
.delete()
.eq('id', id)
if (error) throw error
}
Row Level Security: Policies definieren
RLS-Policies laufen direkt in PostgreSQL und erzwingen Datenzugangsbeschränkungen auf Datenbankebene — egal ob der Request über das SDK, REST API oder SQL kommt.
supabase/migrations/001_rls_policies.sql
-- RLS aktivieren
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE comments ENABLE ROW LEVEL SECURITY;
-- Posts: User sieht nur eigene
CREATE POLICY "users_own_posts" ON posts
FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- Posts: Öffentlich lesbar wenn published = true
CREATE POLICY "public_read_published" ON posts
FOR SELECT
USING (published = true);
-- Comments: Eigene bearbeiten, alle lesen
CREATE POLICY "read_all_comments" ON comments
FOR SELECT USING (true);
CREATE POLICY "insert_own_comments" ON comments
FOR INSERT
WITH CHECK (auth.uid() = author_id);
CREATE POLICY "delete_own_comments" ON comments
FOR DELETE
USING (auth.uid() = author_id);
-- Admin-Rolle: Voller Zugriff via Service Role Key
CREATE POLICY "service_role_all" ON posts
FOR ALL
USING (auth.role() = 'service_role')
WITH CHECK (auth.role() = 'service_role');
Best Practice
Definiere alle Policies als SQL-Migrations in supabase/migrations/. So sind sie versioniert, reproduzierbar und können mit supabase db push auf alle Environments deployed werden — inkl. CI/CD-Integration.
Joins und Relations
lib/data/posts-with-author.ts
// Nested Select: Posts mit Autor-Profil und Kommentaranzahl
const { data } = await supabase
.from('posts')
.select(`
id,
title,
content,
created_at,
profiles (
id,
username,
avatar_url
),
comments ( count )
`)
.eq('published', true)
.order('created_at', { ascending: false })
4. Realtime Subscriptions: Postgres Changes, Broadcast & Presence
Realtime
Supabase Realtime baut auf PostgreSQL's WAL (Write-Ahead Log) auf. Clients verbinden sich via WebSocket und erhalten Push-Notifications bei Datenbankänderungen — ohne Polling, ohne eigenen WebSocket-Server.
Postgres Changes abonnieren
hooks/useRealtimePosts.ts
import { useEffect, useState } from 'react'
import { createClient } from '@/lib/supabase/client'
export function useRealtimePosts() {
const [posts, setPosts] = useState([])
const supabase = createClient()
useEffect(() => {
// Initiale Daten laden
supabase.from('posts').select('*').then(({ data }) => setPosts(data ?? []))
// Realtime Channel für Postgres Changes
const channel = supabase
.channel('posts-changes')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'posts',
filter: 'published=eq.true'
},
(payload) => {
setPosts(prev => [payload.new, ...prev])
}
)
.on(
'postgres_changes',
{ event: 'UPDATE', schema: 'public', table: 'posts' },
(payload) => {
setPosts(prev => prev.map(p => p.id === payload.new.id ? payload.new : p))
}
)
.on(
'postgres_changes',
{ event: 'DELETE', schema: 'public', table: 'posts' },
(payload) => {
setPosts(prev => prev.filter(p => p.id !== payload.old.id))
}
)
.subscribe()
return () => { supabase.removeChannel(channel) }
}, [])
return posts
}
Broadcast: Echtzeit-Nachrichten zwischen Clients
Broadcast ermöglicht das direkte Senden von Events zwischen verbundenen Clients — ideal für kollaborative Features wie Live-Cursor, Chat oder Notifications.
hooks/useLiveChat.ts
const channel = supabase.channel(`room:${roomId}`)
// Nachrichten empfangen
channel.on('broadcast', { event: 'message' }, (payload) => {
setMessages(prev => [...prev, payload.payload])
})
// Nachricht senden
const sendMessage = async (text: string) => {
await channel.send({
type: 'broadcast',
event: 'message',
payload: {
id: crypto.randomUUID(),
text,
user_id: user.id,
timestamp: new Date().toISOString()
}
})
}
channel.subscribe()
Presence: Online-Status und Live-Cursors
hooks/usePresence.ts
const channel = supabase.channel(`doc:${docId}`, {
config: { presence: { key: user.id } }
})
// Presence-Sync: Alle verbundenen User
channel.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState()
setOnlineUsers(Object.values(state).flat())
})
channel.on('presence', { event: 'join' }, ({ newPresences }) => {
console.log('Beigetreten:', newPresences)
})
channel.on('presence', { event: 'leave' }, ({ leftPresences }) => {
console.log('Verlassen:', leftPresences)
})
await channel.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await channel.track({
user_id: user.id,
username: user.user_metadata.username,
cursor: { x: 0, y: 0 },
online_at: new Date().toISOString()
})
}
})
💡 Performance-Tipp: Aktiviere Realtime-Subscriptions nur für Tabellen, die es wirklich brauchen. Im Supabase Dashboard unter Database → Replication kannst du genau steuern, welche Tabellen publiziert werden.
5. Storage & Edge Functions
Storage
Edge Functions
Supabase Storage ist ein S3-kompatibler Object Store mit direkter Integration in das Auth-System. Edge Functions laufen auf Deno in über 300 Regionen weltweit — ohne Cold Starts bei kleinen Funktionen.
Datei-Upload mit Progress
lib/storage/upload.ts
import { createClient } from '@/lib/supabase/client'
export async function uploadAvatar(
userId: string,
file: File,
onProgress?: (percent: number) => void
): Promise<string> {
const supabase = createClient()
const ext = file.name.split('.').pop()
const path = `avatars/${userId}.${ext}`
const { error } = await supabase.storage
.from('public-assets')
.upload(path, file, {
upsert: true,
contentType: file.type,
cacheControl: '3600'
})
if (error) throw error
// Öffentliche URL zurückgeben
const { data } = supabase.storage
.from('public-assets')
.getPublicUrl(path)
return data.publicUrl
}
export async function getSignedUrl(bucket: string, path: string) {
const supabase = createClient()
const { data, error } = await supabase.storage
.from(bucket)
.createSignedUrl(path, 3600) // 1 Stunde gültig
if (error) throw error
return data.signedUrl
}
export async function downloadFile(bucket: string, path: string) {
const supabase = createClient()
const { data, error } = await supabase.storage
.from(bucket)
.download(path)
if (error) throw error
return data // Blob
}
Storage Policies (RLS)
supabase/migrations/002_storage_policies.sql
-- Bucket für private User-Dokumente
INSERT INTO storage.buckets (id, name, public)
VALUES ('user-documents', 'user-documents', false);
-- RLS: User darf nur eigene Dateien sehen
CREATE POLICY "user_own_files" ON storage.objects
FOR ALL USING (
bucket_id = 'user-documents' AND
auth.uid()::text = (storage.foldername(name))[1]
)
WITH CHECK (
bucket_id = 'user-documents' AND
auth.uid()::text = (storage.foldername(name))[1]
);
Edge Functions: Serverless mit Deno
Edge Functions sind TypeScript/Deno-Funktionen, die global verteilt ausgeführt werden. Sie haben Zugriff auf alle Supabase-Services und können externe APIs aufrufen.
supabase/functions/process-upload/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'
serve(async (req) => {
const { file_path, user_id } = await req.json()
// Service-Role-Client für adminisrative Operationen
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
// Datei verarbeiten (z.B. Thumbnail generieren)
const { data: file } = await supabase.storage
.from('uploads')
.download(file_path)
// Embedding generieren (OpenAI / Ollama)
const embeddingRes = await fetch('https://api.openai.com/v1/embeddings', {
method: 'POST',
headers: {
'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ model: 'text-embedding-3-small', input: file_path })
})
const { data: [{ embedding }] } = await embeddingRes.json()
// In Datenbank speichern
await supabase.from('documents').insert({ user_id, file_path, embedding })
return new Response(JSON.stringify({ success: true }), {
headers: { 'Content-Type': 'application/json' }
})
})
bash — Edge Function deployen
# Lokal entwickeln
npx supabase functions serve process-upload --env-file .env.local
# Secrets setzen (einmalig)
npx supabase secrets set OPENAI_API_KEY=sk-...
# Deployen
npx supabase functions deploy process-upload
# Alle Functions deployen
npx supabase functions deploy
6. pgvector & AI: Embedding-Suche für KI-Anwendungen
pgvector & AI
pgvector ist die mächtigste Funktion von Supabase für AI-Applikationen. Es ermöglicht die Speicherung und Suche von Vektoren (Embeddings) direkt in PostgreSQL — keine separate Vektor-Datenbank nötig. Mit Hybrid Search kombinierst du semantische Ähnlichkeit und klassische Volltextsuche.
pgvector Setup: Extension und Schema
supabase/migrations/003_pgvector.sql
-- Extension aktivieren
CREATE EXTENSION IF NOT EXISTS vector;
-- Dokumente-Tabelle mit Embedding-Spalte
CREATE TABLE documents (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
title TEXT NOT NULL,
content TEXT NOT NULL,
embedding vector(1536), -- OpenAI text-embedding-3-small
fts tsvector GENERATED ALWAYS AS (
to_tsvector('german', title || ' ' || content)
) STORED,
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT now()
);
-- HNSW Index für schnelle Vektor-Suche (besser als IVFFlat)
CREATE INDEX documents_embedding_hnsw ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- GIN Index für Volltext-Suche
CREATE INDEX documents_fts_idx ON documents USING gin(fts);
-- RLS aktivieren
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY "users_own_docs" ON documents
FOR ALL USING (auth.uid() = user_id);
match_documents RPC-Funktion
supabase/migrations/004_rpc_match_documents.sql
-- Semantische Ähnlichkeitssuche via RPC
CREATE OR REPLACE FUNCTION match_documents(
query_embedding vector(1536),
match_threshold float DEFAULT 0.75,
match_count int DEFAULT 10
)
RETURNS TABLE (
id UUID,
title TEXT,
content TEXT,
similarity float
)
LANGUAGE sql STABLE
AS $$
SELECT
id,
title,
content,
1 - (embedding <=> query_embedding) AS similarity
FROM documents
WHERE auth.uid() = user_id
AND 1 - (embedding <=> query_embedding) > match_threshold
ORDER BY embedding <=> query_embedding
LIMIT match_count;
$$;
-- Hybrid Search: Vektoren + Volltext kombiniert
CREATE OR REPLACE FUNCTION hybrid_search(
query_text TEXT,
query_embedding vector(1536),
match_count int DEFAULT 10
)
RETURNS TABLE (id UUID, title TEXT, content TEXT, score float)
LANGUAGE sql STABLE
AS $$
WITH semantic AS (
SELECT id, 1 - (embedding <=> query_embedding) AS score
FROM documents
WHERE auth.uid() = user_id
ORDER BY embedding <=> query_embedding
LIMIT match_count * 2
),
fulltext AS (
SELECT id, ts_rank_cd(fts, plainto_tsquery('german', query_text)) AS score
FROM documents
WHERE fts @@ plainto_tsquery('german', query_text)
AND auth.uid() = user_id
LIMIT match_count * 2
)
SELECT d.id, d.title, d.content,
COALESCE(s.score, 0) * 0.7 + COALESCE(ft.score, 0) * 0.3 AS score
FROM documents d
LEFT JOIN semantic s ON d.id = s.id
LEFT JOIN fulltext ft ON d.id = ft.id
WHERE s.id IS NOT NULL OR ft.id IS NOT NULL
ORDER BY score DESC
LIMIT match_count;
$$;
Hybrid Search im TypeScript-Code
lib/ai/search.ts
import { createClient } from '@/lib/supabase/server'
import OpenAI from 'openai'
const openai = new OpenAI()
async function getEmbedding(text: string): Promise<number[]> {
const response = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: text,
})
return response.data[0].embedding
}
export async function semanticSearch(query: string) {
const supabase = await createClient()
const embedding = await getEmbedding(query)
// Reine Vektorsuche via match_documents RPC
const { data, error } = await supabase.rpc('match_documents', {
query_embedding: embedding,
match_threshold: 0.75,
match_count: 10
})
if (error) throw error
return data
}
export async function hybridSearch(query: string) {
const supabase = await createClient()
const embedding = await getEmbedding(query)
// Kombinierte Vektor- + Volltext-Suche
const { data, error } = await supabase.rpc('hybrid_search', {
query_text: query,
query_embedding: embedding,
match_count: 10
})
if (error) throw error
return data
}
export async function indexDocument(
userId: string,
title: string,
content: string
) {
const supabase = await createClient()
const embedding = await getEmbedding(`${title}\n\n${content}`)
const { data, error } = await supabase
.from('documents')
.insert({ user_id: userId, title, content, embedding })
.select('id')
.single()
if (error) throw error
return data.id
}
Supabase vs. Alternativen: Feature-Vergleich 2026
| Feature |
Supabase |
Firebase |
PlanetScale |
Neon |
| PostgreSQL |
✓ Vollständig |
✗ NoSQL |
✓ MySQL |
✓ Vollständig |
| Auth inkl. |
✓ |
✓ |
✗ |
✗ |
| Realtime |
✓ WAL-basiert |
✓ |
✗ |
✗ |
| Storage |
✓ |
✓ |
✗ |
✗ |
| Edge Functions |
✓ Deno |
✓ Node.js |
✗ |
✗ |
| pgvector / AI |
✓ Nativ |
✗ |
✗ |
✓ |
| Row Level Security |
✓ SQL-nativ |
✓ Custom Rules |
✗ |
✗ |
| Open Source |
✓ |
✗ |
✗ |
✓ |
| Self-Hosting |
✓ Docker |
✗ |
✗ |
Teilweise |
| Free Tier |
✓ 2 Projekte |
✓ Spark Plan |
✓ |
✓ |
Claude Code + Supabase: Das optimale Workflow
Workflow
- Schema definieren: Claude Code generiert Migrations aus natürlichsprachigen Requirements
- Types generieren:
npx supabase gen types typescript --linked → vollständige Typisierung
- RLS-Policies: Claude Code analysiert dein Datenmodell und schlägt passende Policies vor
- Edge Functions: Serverless-Logik direkt in deinem Repo, Deployment mit einem Befehl
- pgvector-Integration: Claude Code erstellt Embedding-Pipeline, Indexierung und Search-API
- Testing: Lokale Supabase-Instanz via
supabase start, Tests gegen echte DB
ℹ️ Lokale Entwicklung: Mit npx supabase start startest du eine vollständige lokale Supabase-Instanz (PostgreSQL + Auth + Storage + Realtime) via Docker. Claude Code kann alle Migrations automatisch anwenden und die lokale Instanz für Tests nutzen.
Supabase-Backend in Minuten aufsetzen?
Starte deinen kostenlosen Trial und lass Claude Code dein Supabase-Backend automatisch konfigurieren — Auth, Datenbank, RLS, Realtime und pgvector in einem Rutsch.
Kostenlosen Trial starten →
Kein Kreditkarte erforderlich · Setup in unter 5 Minuten · Jederzeit kündbar