はじめに
個人的に、Supabaseは2024年以降のBaaS(Backend as a Service)選びで最有力候補だと思っています。
GitHubで94,000スター以上、npmパッケージは月間2,500万ダウンロード超え。「オープンソースのFirebase代替」という触れ込みで登場したわけですが、今やFirebaseを超えた存在感を放っています。
正直なところ、最初は「またFirebaseクローンか」と思っていたんですよ。Firebaseで十分じゃない?と。でも実際に触ってみたら、「PostgreSQLがそのまま使える」という一点だけで、かなり印象が変わりました。30代になって思うのは、データベースは後から変えるのが本当に大変だということ。NoSQLで始めて後悔した経験がある人には刺さる話だと思います。
Supabaseとは
SupabaseはPostgreSQLをベースにした開発プラットフォームで、Firebaseのような機能をオープンソースで提供しています。
特徴的なのは、エンタープライズグレードのツールを組み合わせて作られている点。PostgreSQL、Realtime(Elixir製)、PostgREST、GoTrue(認証)、Kong(APIゲートウェイ)など、実績のあるツールが裏で動いています。
「100%ポータブル」を謳っているのもポイント。ベンダーロックインを避けたい人にとっては、これが決め手になることも多いですね。
特徴・メリット
1. PostgreSQLがそのまま使える
これ、意外と重要なんですよ。FirebaseのFirestoreはNoSQLなので、複雑なクエリやJOINが必要になったときに苦労します。
SupabaseはPostgreSQLなので、SQLの知識がそのまま活きる。既存のPostgreSQL資産も移行しやすい。コスパ的に、学習コストの低さは正義です。
2. 自動生成されるAPI
テーブルを作ると、REST APIとGraphQL APIが自動で生成される。これが地味に便利。
個人的には、このAPI自動生成があるおかげで「バックエンド書かなくていい」場面がかなり増えました。
3. リアルタイム同期
データベースの変更をリアルタイムで購読できる。チャットアプリとか、ダッシュボードの自動更新とか、WebSocketを自前で実装しなくて済む。
時短になる機能ですね。
4. 認証機能が標準装備
メール/パスワード、OAuth(Google、GitHub、Twitterなど)、マジックリンク、電話番号認証まで対応。Row Level Security(RLS)との組み合わせで、認可もデータベースレベルで制御できる。
5. ファイルストレージ
S3互換のストレージが付いてくる。画像や動画のアップロード、CDN配信まで一括管理。
6. Edge Functions
サーバーレス関数も実行可能。Deno製で、TypeScriptで書ける。
インストール方法
クラウド版を使う場合
一番簡単なのは、supabase.com でアカウントを作ってプロジェクトを作成する方法。無料プランでも十分使えます。
クライアントライブラリのインストール
npm install @supabase/supabase-js
これだけ。追加パッケージは不要です。
クライアントの初期化
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = 'https://your-project.supabase.co'
const supabaseKey = 'your-anon-key'
const supabase = createClient(supabaseUrl, supabaseKey)
プロジェクトのURLとAPIキーは、ダッシュボードのSettingsから取得できます。
ローカル開発
# Supabase CLIのインストール
npm install -g supabase
# プロジェクトの初期化
supabase init
# ローカル環境の起動
supabase start
Dockerが動いていれば、ローカルで本番と同じ環境が立ち上がる。開発体験として、かなりいい。
基本的な使い方
データの取得(SELECT)
// 全件取得
const { data, error } = await supabase
.from('posts')
.select('*')
// 条件付き取得
const { data, error } = await supabase
.from('posts')
.select('*')
.eq('status', 'published')
.order('created_at', { ascending: false })
.limit(10)
SQLを知っていれば直感的に書ける。これがPostgreSQLベースの強みですね。
リレーションの取得
// 投稿と著者を一緒に取得
const { data, error } = await supabase
.from('posts')
.select(`
*,
author:users(name, avatar_url),
comments(id, content, created_at)
`)
JOINがこんなに簡単に書ける。Firestoreだとこういうのが面倒なんですよ。
データの挿入(INSERT)
const { data, error } = await supabase
.from('posts')
.insert({
title: '新しい記事',
content: '記事の内容',
user_id: 'user-uuid'
})
.select()
データの更新(UPDATE)
const { data, error } = await supabase
.from('posts')
.update({ title: '更新後のタイトル' })
.eq('id', 1)
.select()
データの削除(DELETE)
const { error } = await supabase
.from('posts')
.delete()
.eq('id', 1)
リアルタイム購読
const channel = supabase
.channel('posts-changes')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'posts'
},
(payload) => {
console.log('変更検知:', payload)
}
)
.subscribe()
// 購読解除
channel.unsubscribe()
WebSocketの実装を自分でやる必要がない。これがQOL上がるポイント。
実践的なユースケース
認証の実装
// サインアップ
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'password123'
})
// ログイン
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'password123'
})
// OAuth(Google)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google'
})
// ログアウト
const { error } = await supabase.auth.signOut()
// 現在のユーザー取得
const { data: { user } } = await supabase.auth.getUser()
Row Level Security(RLS)
SQLでアクセス制御を定義できる。これがかなり強力。
-- 自分のデータだけ読める
CREATE POLICY "Users can view own data" ON posts
FOR SELECT
USING (auth.uid() = user_id);
-- 自分のデータだけ更新できる
CREATE POLICY "Users can update own data" ON posts
FOR UPDATE
USING (auth.uid() = user_id);
-- 認証済みユーザーだけ挿入できる
CREATE POLICY "Authenticated users can insert" ON posts
FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
バックエンドでの認可チェックを書かなくていい。セキュリティがデータベースレベルで担保される安心感。
ファイルアップロード
// アップロード
const { data, error } = await supabase.storage
.from('avatars')
.upload(`public/${userId}.png`, file, {
cacheControl: '3600',
upsert: true
})
// 公開URLの取得
const { data } = supabase.storage
.from('avatars')
.getPublicUrl(`public/${userId}.png`)
Next.jsとの統合
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// app/posts/page.tsx
import { supabase } from '@/lib/supabase'
export default async function PostsPage() {
const { data: posts } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
return (
<div>
{posts?.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.content}</p>
</article>
))}
</div>
)
}
Server Componentsでも普通に使える。
Reactカスタムフック
import { useEffect, useState } from 'react'
import { supabase } from '@/lib/supabase'
export function usePosts() {
const [posts, setPosts] = useState<Post[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
// 初回取得
const fetchPosts = async () => {
const { data } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
if (data) setPosts(data)
setLoading(false)
}
fetchPosts()
// リアルタイム購読
const channel = supabase
.channel('posts')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => {
if (payload.eventType === 'INSERT') {
setPosts((prev) => [payload.new as Post, ...prev])
}
if (payload.eventType === 'DELETE') {
setPosts((prev) =>
prev.filter((p) => p.id !== payload.old.id)
)
}
}
)
.subscribe()
return () => {
channel.unsubscribe()
}
}, [])
return { posts, loading }
}
Firebaseからの移行
個人的には、移行する価値は十分あると思います。特に以下のケース:
-
SQLが必要になった
- 複雑なクエリ、JOIN、集計が必要な場合
-
ベンダーロックインを避けたい
- PostgreSQLなので、他のサービスへの移行も容易
-
オープンソースが好み
- セルフホストも可能
移行のポイント:
- FirestoreのドキュメントをPostgreSQLのテーブルに変換
- Cloud FunctionsをEdge Functionsに書き換え
- 認証は似た仕組みなので比較的楽
まとめ
Supabaseを導入して感じた変化:
- セットアップ: 20分でauth+database+リアルタイムが動く
- 学習コスト: SQLを知っていればほぼゼロ
- 開発速度: バックエンドを書く時間が激減
- 柔軟性: PostgreSQLなので何でもできる安心感
- コスト: 無料プランでも十分使える
正直なところ、新規プロジェクトでFirebaseを選ぶ理由はかなり限られると思います。NoSQLが必須とか、GCPとの連携が必要とか、そういう場合以外はSupabase一択ですね。
特に「SQLの方が慣れている」「将来的にスケールしたい」「オープンソースが好き」という人には最適。バックエンド構築で消耗していた時間を取り戻せますよ。
まだ試していない人は、まず小さなプロジェクトで使ってみてください。「なんでもっと早く使わなかったんだ」と思うはずです。