Supabase
CloudEn open-source Firebase alternative bygget på PostgreSQL med realtime subscriptions, authentication og storage.
Beskrivelse
Supabase markedsføres som 'The Open Source Firebase Alternative' og giver udviklere et komplet backend-as-a-service platform. I kernen ligger en fuldt managed PostgreSQL database, men Supabase tilføjer et lag af developer-friendly features ovenpå: auto-generated REST og GraphQL APIs, realtime subscriptions (lyt til database changes), built-in authentication (email, OAuth, magic links), file storage, og edge functions. Alt dette er open source og kan self-hostes. Supabase Philosophy er at bruge battle-tested open source tools (PostgreSQL, PostgREST, GoTrue) i stedet for at genopfinde hjulet. Fordi det er PostgreSQL under the hood, får du alle PostgreSQL's kraftfulde features: SQL, JOINs, foreign keys, views, functions, triggers, og RLS (Row Level Security) til granular permissions. Supabase Dashboard giver en brugervenlig interface til at browse data, skrive SQL, manage users, og monitor performance. Det er perfekt til moderne web og mobile apps hvor du vil have backend infrastructure uden at administrere servere.
Features
- •PostgreSQL database (auto-scaling)
- •Auto-generated REST API
- •Realtime subscriptions
- •Built-in authentication
- •File storage med CDN
- •Edge Functions (Deno)
- •Row Level Security (RLS)
- •Database webhooks
Query Eksempel
-- Supabase Dashboard SQL Editor
-- 1. Opret tabel
CREATE TABLE posts (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
author_id UUID REFERENCES auth.users NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
published BOOLEAN DEFAULT false
);
-- 2. Enable Row Level Security
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- 3. RLS Policies
-- Anyone can read published posts
CREATE POLICY "Public posts are viewable by everyone"
ON posts FOR SELECT
USING (published = true);
-- Users can insert their own posts
CREATE POLICY "Users can insert their own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = author_id);
-- Users can update their own posts
CREATE POLICY "Users can update own posts"
ON posts FOR UPDATE
USING (auth.uid() = author_id);
-- 4. Database Function
CREATE OR REPLACE FUNCTION get_user_posts(user_uuid UUID)
RETURNS SETOF posts AS $$
SELECT * FROM posts WHERE author_id = user_uuid;
$$ LANGUAGE sql STABLE;
-- JavaScript Client (supabase-js)
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
)
// 1. Authentication
const { data, error } = await supabase.auth.signUp({
email: 'user@email.com',
password: 'password123'
})
// Login
const { data: session } = await supabase.auth.signInWithPassword({
email: 'user@email.com',
password: 'password123'
})
// 2. Insert data (auto-generated API)
const { data: post, error } = await supabase
.from('posts')
.insert({
title: 'Min første post',
content: 'Dette er content',
author_id: session.user.id
})
.select()
// 3. Query data
const { data: posts } = await supabase
.from('posts')
.select('*, author:author_id(name, email)')
.eq('published', true)
.order('created_at', { ascending: false })
.limit(10)
// 4. Realtime subscription
const channel = supabase
.channel('posts-channel')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'posts'
},
(payload) => {
console.log('Change received!', payload)
}
)
.subscribe()
// 5. Update
const { data } = await supabase
.from('posts')
.update({ published: true })
.eq('id', postId)
// 6. Delete
const { error } = await supabase
.from('posts')
.delete()
.eq('id', postId)
// 7. File Storage
const { data: uploadData } = await supabase
.storage
.from('avatars')
.upload('user-avatar.png', file)
const { data: url } = supabase
.storage
.from('avatars')
.getPublicUrl('user-avatar.png')
// 8. Edge Functions
const { data: result } = await supabase.functions.invoke('hello-world', {
body: { name: 'Peter' }
})
// 9. RPC (call database function)
const { data } = await supabase
.rpc('get_user_posts', { user_uuid: userId })
// React eksempel med realtime
import { useEffect, useState } from 'react'
function Posts() {
const [posts, setPosts] = useState([]
useEffect(() => {
// Fetch initial data
fetchPosts()
// Subscribe to changes
const channel = supabase
.channel('posts')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
handleChange
)
.subscribe()
return () => supabase.removeChannel(channel)
}, [])
const fetchPosts = async () => {
const { data } = await supabase.from('posts').select('*')
setPosts(data)
}
const handleChange = (payload) => {
if (payload.eventType === 'INSERT') {
setPosts(prev => [...prev, payload.new])
}
// Handle UPDATE and DELETE...
}
return <div>{/* Render posts */}</div>
}Anvendelsesområder
- •Rapid prototyping og MVPs
- •SaaS applikationer
- •Mobile apps med realtime features
- •Jamstack websites med dynamic content
- •Indie hacker projekter
Fordele
- ✓Komplet backend i én platform
- ✓PostgreSQL's kraft og fleksibilitet
- ✓Open source - kan self-hostes
- ✓Generous free tier
- ✓Excellent developer experience
Ulemper
- ✗Vendor lock-in hvis du bruger Supabase-specific features
- ✗Kan blive dyrt ved scale
- ✗Mindre kontrol end self-hosted løsning
- ✗Realtime kun på hosted version (ikke self-hosted)
- ✗Relativt nyt (mindre mature end Firebase)
Bedst til
- →Moderne web apps med realtime requirements
- →Mobile apps (Flutter, React Native)
- →Jamstack sites med dynamic data
- →Prototyper og MVPs
- →Indie projects med budget constraints
Ikke anbefalet til
- ⚠Enterprise med strenge compliance krav
- ⚠Ultra-high scale (millioner af users)
- ⚠Applications med complex backend logic
- ⚠Når du har brug for fuld kontrol over infrastructure
- ⚠Legacy systems der ikke kan migreres