Supabaseとは?Firebaseとの違いを理解する
Supabaseの概要 — 「オープンソース版Firebase」の実力
Supabaseは、2020年に設立されたオープンソースのBaaS(Backend as a Service)プラットフォームです。 「The Open Source Firebase Alternative」を掲げ、Firebaseが提供する機能をPostgreSQLベースで 再構築しています。
最大の特徴は、バックエンドに必要なほぼすべての機能がひとつのダッシュボードに統合されていることです。具体的には以下の機能が含まれます。
- Database: PostgreSQLベースのリレーショナルデータベース
- Auth: メール/パスワード、OAuth(Google、GitHub等)、Magic Linkなど多様な認証
- Storage: 画像・動画・PDFなどのファイルストレージ
- Edge Functions: Deno Deployベースのサーバーレス関数
- Realtime: WebSocketを使ったリアルタイムデータ同期
- Vector: AI/ML向けのベクトル検索(pgvector統合)
- Cron: スケジュール実行ジョブ(pg_cron統合)
ShiftBでは受講生の個人開発プロジェクトでSupabaseの採用率が82%に達しています。 理由はシンプルで、「バックエンドの構築時間を1/5に短縮できるから」です。 従来のExpress + PostgreSQL + Prismaの構成では平均40時間かかっていたバックエンド構築が、 Supabaseでは平均8時間で完了しています。
Supabase vs Firebase — 7つの観点で徹底比較
「Firebase と何が違うの?」は最もよく聞かれる質問です。 両者を7つの観点で比較します。
| 比較項目 | Supabase | Firebase |
|---|
| データベース | PostgreSQL(リレーショナル) | Firestore(NoSQL) |
| クエリ言語 | SQL(標準的) | 独自API |
| オープンソース | 完全OSS(セルフホスト可) | プロプライエタリ |
| 認証 | GoTrue(OSS) | Firebase Auth |
| リアルタイム | WebSocket(Realtime) | Firestore Listener(強力) |
| 料金体系 | 無料枠が大きい | 読み書き回数課金 |
| ベンダーロックイン | 低い(PostgreSQL標準) | 高い(Google依存) |
個人開発者にとって最も重要な違いはデータベースの種類です。 FirebaseのFirestoreはNoSQLで、データの関連性(リレーション)を表現するのが苦手です。 例えば「ユーザーが投稿した記事の一覧をタグでフィルタリング」のような処理は、 Firestoreでは複雑になりますが、SupabaseのPostgreSQLならSQLのJOINで直感的に書けます。
一方、Firebaseが優れているのはリアルタイム通信の成熟度です。 チャットアプリなどリアルタイム性が最も重要な場合はFirebaseに分があります。 ただし、Supabaseのリアルタイム機能も2025年以降大幅に改善されており、 多くのユースケースでは十分です。
Supabase vs その他のBaaS — 選定基準
| サービス | 特徴 | 向いている用途 | 個人開発の推奨度 |
|---|
| Supabase | PostgreSQL、認証・ストレージ統合 | Webアプリ全般 | ★★★★★ |
| Firebase | NoSQL、Google統合 | モバイル、リアルタイムチャット | ★★★★☆ |
| PlanetScale | MySQL、ブランチング | 大規模DB運用 | ★★★☆☆ |
| Neon | サーバーレスPostgreSQL | DBのみ必要な場合 | ★★★★☆ |
| Appwrite | セルフホスト前提のBaaS | セルフホスト重視 | ★★★☆☆ |
結論として、個人開発でWebアプリを作るなら、2026年時点でSupabaseが最もバランスの良い選択肢です。PostgreSQLの汎用性、無料枠の大きさ、認証・ストレージの統合、 そしてNext.jsとの親和性の高さが決め手になります。

Supabaseの料金プラン完全比較【2026年最新】
全プランの機能・制限を一覧で比較
Supabaseの料金プランは4つあります。個人開発では99%のケースで FreeプランまたはProプランで十分です。

| 項目 | Free | Pro | Team | Enterprise |
|---|
| 月額料金 | $0 | $25 | $599 | 要問い合わせ |
| データベース容量 | 500MB | 8GB | 8GB | カスタム |
| ストレージ | 1GB | 100GB | 100GB | カスタム |
| 月間認証ユーザー(MAU) | 50,000 | 100,000 | 100,000 | カスタム |
| Edge Functions呼び出し | 500K/月 | 2M/月 | 2M/月 | カスタム |
| プロジェクト数 | 2つまで | 無制限 | 無制限 | 無制限 |
| DB一時停止 | 1週間未使用で停止 | 停止なし | 停止なし | 停止なし |
| バックアップ | なし | 日次(7日間保持) | 日次(7日間保持) | カスタム |
個人開発のフェーズ別おすすめプラン
ShiftBの受講生データから、開発フェーズに応じた最適なプラン選択を解説します。
| 開発フェーズ | 推奨プラン | 月額 | 判断基準 |
|---|
| 学習・プロトタイプ | Free | $0 | ユーザー数0〜100人 |
| β版・初期リリース | Free | $0 | ユーザー数100〜1,000人 |
| 本格運用(収益化開始) | Pro | $25 | ユーザー数1,000〜10,000人 |
| グロース期 | Pro + 従量課金 | $25+α | ユーザー数10,000人〜 |
ポイントは、Freeプランの無料枠が非常に大きいことです。 MAU 50,000人、データベース500MBは、個人開発の初期段階では十分すぎる容量です。 ShiftBの受講生で最も多いパターンは、 「Freeプランで開発・リリース → 月間ユーザー1,000人を超えたらProプランに移行」 という流れです。
注意点として、Freeプランでは1週間アクセスがないとデータベースが一時停止される仕様があります。 ダッシュボードから手動で再開できますが、本番サービスを運用する場合はProプランへの移行をおすすめします。
Firebaseとの料金比較 — 実際にいくら違うのか
Firebaseは読み書き回数に応じた従量課金のため、トラフィックが増えるとコストが急増しやすい構造です。 月間アクティブユーザー5,000人のWebアプリを想定して比較します。
| 利用規模(MAU 5,000) | Supabase Pro | Firebase Blaze |
|---|
| 基本料金 | $25/月 | $0(従量課金) |
| DB読み取り(100万回/月) | Proに含まれる | 約$0.36 |
| DB書き込み(20万回/月) | Proに含まれる | 約$0.18 |
| ストレージ(5GB) | Proに含まれる | 約$0.13 |
| 認証 | Proに含まれる | 無料 |
| 月額合計(目安) | $25 | $15〜40 |
小規模ではFirebaseの方が安くなるケースもありますが、Supabaseは定額制のため予測可能性が高いのが個人開発者にとって大きなメリットです。 「今月の請求がいくらになるか分からない」という不安がありません。
AI時代のアプリ開発コース
ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながらAI駆動開発を身につけるコースです。ただ作って終わりではなく、コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担えるところまで現役エンジニアがサポートします。
AIシフトコースを見る →Supabaseの始め方 — プロジェクト作成から初期設定まで
Step 1: Supabaseアカウントの作成(所要時間: 2分)
Supabaseの公式サイト(supabase.com)にアクセスし、 「Start your project」をクリックします。GitHubアカウントでのサインアップが最も簡単です。
- GitHubアカウントでサインイン
- Supabaseへのアクセスを許可
- ダッシュボードが表示されれば完了
Step 2: 新規プロジェクトの作成(所要時間: 3分)
ダッシュボードから「New Project」をクリックし、以下の設定を行います。
- Organization: デフォルトでOK(後から変更可能)
- Project name: プロジェクト名(例: my-todo-app)
- Database Password: 強力なパスワードを設定(後で使うので必ずメモ)
- Region: Northeast Asia (Tokyo) を選択
- Pricing Plan: Free(個人開発ならまずFreeで十分)
リージョンは必ずTokyo(ap-northeast-1)を選んでください。日本のユーザーがメインなら、東京リージョンを選ぶことでレイテンシが約200ms → 約30msに改善されます。これはユーザー体験に直結する差です。
Step 3: APIキーの確認と環境変数の設定(所要時間: 5分)
プロジェクトが作成されたら、Settings → API で以下の情報を確認します。
- Project URL:
https://xxxxx.supabase.co - anon key: クライアント側で使う公開キー
- service_role key: サーバー側で使う秘密キー(絶対に公開しない)
Next.jsプロジェクトの場合、.env.local に以下のように設定します。
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbG...(anon key)
重要: service_role キーは NEXT_PUBLIC_ を付けないでください。クライアント側に露出すると、データベースのRLS(Row Level Security)を バイパスして全データにアクセスできてしまいます。
Step 4: Supabase CLIのインストール(所要時間: 3分)
ローカルでの開発やマイグレーション管理にはSupabase CLIが便利です。
# macOS(Homebrew)
brew install supabase/tap/supabase
# npm
npm install -g supabase
# バージョン確認
supabase --version
CLIをインストールしたら、プロジェクトを初期化します。
# プロジェクトディレクトリで実行
supabase init
# ログイン
supabase login
# リモートプロジェクトとリンク
supabase link --project-ref your-project-id
Step 5: Supabase JSクライアントのセットアップ(所要時間: 5分)
Next.jsプロジェクトにSupabaseクライアントライブラリをインストールします。
npm install @supabase/supabase-js @supabase/ssr
クライアントの初期化コードを作成します。
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
// lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
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);
});
},
},
}
);
}
ポイント: @supabase/ssrパッケージを使うことで、 Next.jsのServer Components / Route Handlers / Middlewareすべてで Supabaseクライアントを安全に使えます。App Routerを使う場合は必須のパッケージです。
データベース(PostgreSQL)の使い方を実践解説
テーブルの作成 — GUIとSQLの2つの方法
Supabaseでテーブルを作成する方法は2つあります。
方法1: Table Editor(GUI)で視覚的に作成する方法。 ダッシュボードの「Table Editor」タブから、カラム名・型・制約を入力して作成できます。 プログラミング初心者やプロトタイプ段階におすすめです。
方法2: SQL Editorで直接SQLを書く方法。 本格的な開発では、再現性と履歴管理のためSQLを推奨します。
-- ユーザープロフィールテーブル
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
display_name TEXT,
avatar_url TEXT,
bio TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 投稿テーブル
CREATE TABLE posts (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES profiles(id) ON DELETE CASCADE NOT NULL,
title TEXT NOT NULL,
content TEXT,
published BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- タグテーブル
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);
-- 投稿×タグの中間テーブル
CREATE TABLE post_tags (
post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
tag_id INT REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (post_id, tag_id)
);
RLS(Row Level Security)— 最も重要なセキュリティ設定
SupabaseでPostgreSQLを使う上で、最も理解すべき概念がRLSです。 RLSは「誰がどのデータにアクセスできるか」をデータベースレベルで制御する仕組みです。
RLSを有効にしないと、anonキーを持つ誰でも全データを読み書きできてしまいます。これは個人開発でよくあるセキュリティ事故の原因です。
-- RLSを有効化
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- profiles: 自分のデータだけ読み書き可能
CREATE POLICY "Users can view own profile"
ON profiles FOR SELECT
USING (auth.uid() = id);
CREATE POLICY "Users can update own profile"
ON profiles FOR UPDATE
USING (auth.uid() = id);
-- posts: 公開記事は誰でも読める、作成・編集は本人のみ
CREATE POLICY "Anyone can view published posts"
ON posts FOR SELECT
USING (published = true);
CREATE POLICY "Users can view own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can create own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own posts"
ON posts FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own posts"
ON posts FOR DELETE
USING (auth.uid() = user_id);
ShiftBでよくある失敗パターン: テーブルを作ったのにデータが取得できない。 原因の90%は「RLSを有効にしたがポリシーを設定していない」です。 RLSを有効にした時点で、ポリシーがないテーブルはすべてのアクセスがブロックされます。
CRUD操作 — Supabase JSクライアントの基本
Supabaseのクライアントライブラリを使った基本的なCRUD操作を見ていきます。
import { createClient } from "@/lib/supabase/client";
const supabase = createClient();
// CREATE: データの挿入
const { data, error } = await supabase
.from("posts")
.insert({
user_id: userId,
title: "はじめての投稿",
content: "Supabaseで作りました!",
published: true,
})
.select()
.single();
// READ: データの取得(フィルタリング・ソート)
const { data: posts } = await supabase
.from("posts")
.select("*, profiles(username, avatar_url)")
.eq("published", true)
.order("created_at", { ascending: false })
.limit(10);
// UPDATE: データの更新
const { error } = await supabase
.from("posts")
.update({ title: "タイトルを変更しました" })
.eq("id", postId);
// DELETE: データの削除
const { error } = await supabase
.from("posts")
.delete()
.eq("id", postId);
特に便利なのが.select()でのリレーション指定です。select("*, profiles(username, avatar_url)") と書くだけで、 外部キーで関連するprofilesテーブルのデータを自動でJOINして取得できます。 Firebase(Firestore)ではこのような関連データの取得に2回のクエリが必要ですが、 Supabaseなら1回で完結します。
マイグレーション管理 — チームや複数環境での開発
Supabase CLIを使えば、データベースの変更履歴をSQLファイルで管理できます。
# マイグレーションファイルを作成
supabase migration new create_profiles_table
# 生成されたファイル(supabase/migrations/xxxxx_create_profiles_table.sql)にSQLを書く
# ローカルDBに適用
supabase db reset
# リモート(本番)に適用
supabase db push
マイグレーションを使うことで、「ダッシュボードで直接テーブルを変更したら、 開発環境と本番環境がズレてしまった」という事故を防げます。個人開発でも、初期段階からマイグレーションを使う習慣をつけることを強く推奨します。

認証(Auth)機能でユーザー管理を実装する
Supabase Authが対応する認証方法一覧
Supabase Authは20種類以上の認証方法に対応しています。 個人開発で特によく使われるものを整理します。
| 認証方法 | 実装の手間 | ユーザー体験 | おすすめ用途 |
|---|
| メール + パスワード | ★☆☆(簡単) | ★★★☆☆ | 基本の認証 |
| Magic Link(メール) | ★☆☆(簡単) | ★★★★☆ | パスワードレスログイン |
| Google OAuth | ★★☆(中程度) | ★★★★★ | 最も推奨 |
| GitHub OAuth | ★★☆(中程度) | ★★★★☆ | 開発者向けサービス |
| Apple Sign In | ★★★(やや複雑) | ★★★★★ | iOS連携 |
| OTP(SMS) | ★★☆(中程度) | ★★★★☆ | 電話番号認証 |
ShiftBの受講生に最も人気なのはGoogle OAuthです。 ユーザーの78%がGoogleログインを選択するというデータがあります(ShiftB受講生のサービス計測データ)。 個人開発では、まずGoogle OAuthだけ実装し、 必要に応じて他の認証方法を追加するのが効率的です。
メール + パスワード認証の実装
最もシンプルな認証の実装例です。
// サインアップ
const { data, error } = await supabase.auth.signUp({
email: "user@example.com",
password: "securePassword123",
});
// ログイン
const { data, error } = await supabase.auth.signInWithPassword({
email: "user@example.com",
password: "securePassword123",
});
// ログアウト
await supabase.auth.signOut();
// 現在のユーザー取得
const { data: { user } } = await supabase.auth.getUser();
Google OAuthの実装(最もおすすめ)
Google OAuthの実装は以下の3ステップで完了します。
Step 1: Google Cloud Consoleでの設定
- Google Cloud ConsoleでプロジェクトのOAuth同意画面を設定
- 認証情報でOAuth 2.0クライアントIDを作成
- 承認済みリダイレクトURIに
https://xxxxx.supabase.co/auth/v1/callback を追加
Step 2: Supabaseダッシュボードでの設定
- Authentication → Providers → Google を有効化
- Client ID と Client Secret を入力
Step 3: フロントエンドの実装
// Google OAuthログイン
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
});
// app/auth/callback/route.ts(Next.js App Router)
import { createClient } from "@/lib/supabase/server";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get("code");
if (code) {
const supabase = await createClient();
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(`${origin}/dashboard`);
}
たったこれだけで、Googleログインが完成します。Firebase Authと比べても実装の手軽さは同等で、 かつSupabaseの場合はユーザーデータがauth.usersテーブルに PostgreSQLで保存されるため、カスタムクエリが自由にできるメリットがあります。
認証ユーザーのプロフィール自動作成(トリガー活用)
新規ユーザーがサインアップしたら、自動でprofilesテーブルにレコードを作成するトリガーを設定します。 これは個人開発で必ず使うパターンです。
-- トリガー関数の作成
CREATE OR REPLACE FUNCTION handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, username, display_name, avatar_url)
VALUES (
NEW.id,
NEW.raw_user_meta_data->>'preferred_username',
NEW.raw_user_meta_data->>'full_name',
NEW.raw_user_meta_data->>'avatar_url'
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- トリガーの設定
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION handle_new_user();
AI時代のアプリ開発コース
ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながらAI駆動開発を身につけるコースです。ただ作って終わりではなく、コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担えるところまで現役エンジニアがサポートします。
AIシフトコースを見る →Storageでファイルアップロードを実装する
Supabase Storageの基本概念
Supabase Storageは、S3互換のオブジェクトストレージです。 画像・動画・PDFなどのファイルをアップロード・管理できます。
ストレージは「バケット」単位で管理されます。バケットには公開(public)と非公開(private)の2種類があります。
| バケットタイプ | アクセス制御 | 用途例 |
|---|
| Public | URLを知っていれば誰でもアクセス可 | ユーザーアバター、ブログ画像 |
| Private | RLSポリシーで制御 | 請求書、個人データ |
バケットの作成とファイルアップロード
-- SQLでバケットを作成
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- RLSポリシーの設定
CREATE POLICY "Anyone can view avatars"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "Authenticated users can upload avatars"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars'
AND auth.role() = 'authenticated'
);
フロントエンドでのアップロード実装は以下のようになります。
// ファイルアップロード
const handleUpload = async (file: File) => {
const fileExt = file.name.split(".").pop();
const fileName = `${userId}/${Date.now()}.${fileExt}`;
const { data, error } = await supabase.storage
.from("avatars")
.upload(fileName, file, {
cacheControl: "3600",
upsert: true,
});
if (error) throw error;
// 公開URLの取得
const { data: { publicUrl } } = supabase.storage
.from("avatars")
.getPublicUrl(fileName);
return publicUrl;
};
画像の自動リサイズ(Image Transformation)
Supabase Storageには画像の自動変換機能が組み込まれています。 URLパラメータを追加するだけで、リサイズ・品質変更・フォーマット変換ができます。
// 元画像のURL
const originalUrl = supabase.storage
.from("avatars")
.getPublicUrl("user1/avatar.png");
// 200x200にリサイズ
const thumbnailUrl = supabase.storage
.from("avatars")
.getPublicUrl("user1/avatar.png", {
transform: {
width: 200,
height: 200,
resize: "cover",
},
});
これにより、アバター表示時にフルサイズの画像を読み込む無駄を省き、ページの表示速度を30〜50%改善できます。 ShiftBのサービスでもこの機能を活用しており、画像最適化の実装工数がほぼゼロになりました。
Next.js × Supabaseで個人開発アプリを作る実践ガイド
技術スタック全体像 — なぜNext.js × Supabaseなのか
ShiftBが個人開発で推奨する技術スタックは以下の通りです。
| レイヤー | 技術 | 役割 |
|---|
| フロントエンド | Next.js(App Router) | React + SSR/SSG + APIルート |
| バックエンド | Supabase | DB + 認証 + ストレージ |
| ホスティング | Vercel | デプロイ + CDN + ドメイン |
| 決済 | Stripe | サブスクリプション・単発決済 |
| スタイリング | Tailwind CSS | ユーティリティファーストCSS |
この構成の最大のメリットは、すべてのサービスに無料枠があり、 月額$0で本番サービスを運用開始できることです。 ShiftB受講生の93%がこの構成でプロダクトをリリースしています。
Server Componentsでのデータ取得パターン
Next.js App Routerでは、Server Componentsから直接Supabaseのデータを取得できます。 これにより、クライアント側にJavaScriptを送信する必要がなく、初期表示速度が大幅に改善されます。
// app/posts/page.tsx(Server Component)
import { createClient } from "@/lib/supabase/server";
export default async function PostsPage() {
const supabase = await createClient();
const { data: posts } = await supabase
.from("posts")
.select(`
*,
profiles(username, avatar_url),
post_tags(tags(name))
`)
.eq("published", true)
.order("created_at", { ascending: false })
.limit(20);
return (
<div className="mx-auto max-w-3xl px-4 py-8">
<h1 className="mb-8 text-3xl font-bold">記事一覧</h1>
<div className="flex flex-col gap-6">
{posts?.map((post) => (
<article key={post.id} className="rounded-lg border p-6">
<h2 className="text-xl font-semibold">{post.title}</h2>
<p className="mt-2 text-gray-600">
by {post.profiles.username}
</p>
</article>
))}
</div>
</div>
);
}
Client Componentsでのリアルタイム更新パターン
いいね数の即座更新や、チャットメッセージのリアルタイム表示など、 動的な機能にはClient Componentsを使います。
"use client";
import { createClient } from "@/lib/supabase/client";
import { useEffect, useState } from "react";
export function LikeButton({ postId, initialCount }: {
postId: string;
initialCount: number;
}) {
const [count, setCount] = useState(initialCount);
const supabase = createClient();
useEffect(() => {
// リアルタイムサブスクリプション
const channel = supabase
.channel(`post-${postId}`)
.on(
"postgres_changes",
{
event: "UPDATE",
schema: "public",
table: "posts",
filter: `id=eq.${postId}`,
},
(payload) => {
setCount(payload.new.like_count);
}
)
.subscribe();
return () => { supabase.removeChannel(channel); };
}, [postId, supabase]);
const handleLike = async () => {
await supabase.rpc("increment_like", { post_id: postId });
};
return (
<button onClick={handleLike} className="flex items-center gap-2">
♥ {count}
</button>
);
}
Middlewareでの認証チェックパターン
特定のページへのアクセスをログインユーザーに限定する場合、 Next.jsのMiddlewareを使います。
// middleware.ts
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function middleware(request: NextRequest) {
let supabaseResponse = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => {
request.cookies.set(name, value);
supabaseResponse.cookies.set(name, value, options);
});
},
},
}
);
const { data: { user } } = await supabase.auth.getUser();
// 未ログインなら /login にリダイレクト
if (!user && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return supabaseResponse;
}
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*"],
};
型安全な開発 — Supabase型自動生成
Supabase CLIを使うと、データベーススキーマからTypeScriptの型定義を自動生成できます。これにより、型の不一致によるバグを防げます。
# 型定義の生成
supabase gen types typescript --project-id your-project-id > lib/supabase/database.types.ts
# 生成されたら、クライアント初期化時に型を渡す
import { Database } from "@/lib/supabase/database.types";
const supabase = createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// これで supabase.from("posts") の戻り値に型が付く!
const { data } = await supabase
.from("posts")
.select("title, content"); // ← title, contentの型が自動推論される
ShiftBでの実践Tips: 型生成コマンドはpackage.jsonのscriptsに登録しておくと便利です。"db:types": "supabase gen types typescript --project-id $PROJECT_ID > lib/supabase/database.types.ts"として、テーブル変更時にnpm run db:typesを実行する習慣をつけましょう。

よくある質問(FAQ)
Q1. プログラミング初心者でもSupabaseは使えますか?
はい、使えます。Supabaseのダッシュボードは直感的に操作できるGUIがあり、 テーブル作成やデータ閲覧はSQLを書かなくても可能です。 ただし、RLS(セキュリティ設定)やマイグレーション管理にはSQLの基礎知識が必要です。 ShiftBでは、SQLの基礎(SELECT/INSERT/UPDATE/DELETE)を3日程度で学んでからSupabaseに入ることを推奨しています。
Q2. Supabaseの無料プランでどこまでできますか?
Freeプランでは、データベース500MB、ストレージ1GB、MAU 50,000人まで利用できます。 個人開発の初期〜中期段階では十分な容量です。 ShiftBの受講生では、月間1,000ユーザーを超えるまでFreeプランで運用している方が大半です。 ただし、1週間アクセスがないとDBが一時停止する点にはご注意ください。
Q3. Supabaseのデータは安全ですか?バックアップは取れますか?
Supabaseはデータの暗号化(保存時・転送時)に対応しています。 Proプランでは日次バックアップ(7日間保持)が標準で含まれます。 Freeプランではバックアップがないため、重要なデータはpg_dumpを使って定期的に手動バックアップすることを推奨します。 また、RLSを正しく設定することで、ユーザー間のデータ漏洩を防げます。
Q4. SupabaseからFirebaseに移行(またはその逆)はできますか?
SupabaseはPostgreSQL標準に準拠しているため、他のPostgreSQLホスティング(Neon、Railway、自前サーバーなど)への移行は容易です。pg_dumpとpg_restoreで完全なデータ移行が可能です。 一方、Firebase(Firestore)からの移行はデータ構造が異なるため、変換スクリプトの作成が必要です。 逆に、FirestoreのNoSQL構造にSupabaseのリレーショナルデータを変換するのも一手間かかります。
Q5. バイブコーディング(AIコーディング)とSupabaseの相性はどうですか?
非常に良いです。SupabaseはPostgreSQL標準のSQLを使うため、 Claude CodeやCursorなどのAIツールがSQLやクライアントコードを正確に生成できます。 ShiftBの受講生でも、AIを使ってSupabaseのRLSポリシーやCRUD処理を生成し、 開発時間をさらに50%短縮している事例が多数あります。 「テーブル設計だけ自分で考え、実装はAIに任せる」というワークフローが最も効率的です。
Q6. Edge Functionsは使うべきですか?
Edge Functionsは、Webhookの受信(Stripe決済通知など)、 外部API連携、複雑なデータ処理に使います。 ただし、Next.jsのAPI Routes(Route Handlers)で代替できるケースが多いため、 まずはRoute Handlersで実装し、Supabaseのダッシュボード内で完結させたい処理だけ Edge Functionsを使うのがおすすめです。
Q7. Supabaseを学ぶのにおすすめの学習順序は?
以下の順序で学ぶことを推奨します。
- SQLの基礎(SELECT, INSERT, UPDATE, DELETE, JOIN)— 3日
- Supabaseダッシュボード操作(テーブル作成、データ入力、SQL Editor)— 1日
- 認証(Auth)の実装(メール認証 → Google OAuth)— 2日
- RLSの理解と設定 — 1日
- Next.jsとの連携(CRUD、Server Components)— 3日
- Storageの活用(画像アップロード)— 1日
- 実際のアプリを1つ作る — 5〜7日
合計で約2〜3週間あれば、Supabaseを使った個人開発アプリを1つリリースできるレベルになります。
まとめ — Supabaseで個人開発のバックエンドを最速で構築しよう
この記事では、Supabaseの基礎から実践的なNext.jsとの連携まで、 個人開発で必要な知識を網羅的に解説しました。最後に要点をまとめます。
- Supabaseは「オープンソース版Firebase」。PostgreSQLベースで、DB・認証・ストレージが統合されている
- Firebaseとの最大の違いはRDB。SQLのJOINが使えるため、リレーショナルなデータ構造に強い
- Freeプランで十分始められる。MAU 50,000人、DB 500MBは個人開発の初期段階で十分
- RLSの設定は必須。セキュリティの要であり、設定漏れはデータ漏洩に直結する
- Next.js App Routerとの相性が抜群。Server Components + Supabaseで高速なWebアプリが作れる
- 型の自動生成でTypeScriptとの連携も万全。バグの少ない堅牢なコードが書ける
- AIコーディングとの相性も良い。SQL標準に準拠しているため、AIツールが正確にコードを生成できる
ShiftBでは、Supabaseを使った個人開発を企画からリリースまで一気通貫でサポートしています。 「Supabaseで何か作ってみたいけど、何から始めればいいか分からない」という方は、 ぜひ無料相談会にお越しください。あなたのアイデアに合わせた技術スタックと開発プランを一緒に考えます。