ツール··25min read

Supabaseの使い方を徹底解説【個人開発の最強バックエンド入門】

Supabaseバックエンド個人開発Next.jsPostgreSQLBaaS
Supabaseの使い方を徹底解説【個人開発の最強バックエンド入門】

「バックエンドの構築に時間がかかりすぎて、いつまでもプロダクトがリリースできない」—— 個人開発者の約67%が抱える悩みです(ShiftB受講生アンケート、2025年実施)。

その解決策として、いま最も注目されているのがSupabaseです。 PostgreSQLベースのオープンソースBaaS(Backend as a Service)で、 データベース・認証・ストレージ・リアルタイム通信をひとつのダッシュボードで管理できます。2024年にはシリーズDで2億ドルを調達し、 GitHub Starは78,000超。個人開発者からスタートアップまで、 採用が急拡大しています。

この記事では、ShiftBで142名以上の受講生にSupabaseを使った個人開発を指導してきた筆者が、 Supabaseの使い方をゼロから徹底解説します。プロジェクト作成・データベース設計・認証実装・ ファイルアップロード・Next.jsとの連携まで、この1記事を読めばSupabaseで個人開発を始められる構成になっています。

この記事を書いた人:立川修平(ぶべ)

  • ShiftB校長。受講生142名の個人開発をサポートし、Supabaseの採用率82%の実績
  • 自社サービスを含む複数のWebアプリをNext.js × Supabaseで開発・運営中
  • SNSフォロワー計3万人超。個人開発・AI駆動開発の情報を毎日発信

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つの観点で比較します。

比較項目SupabaseFirebase
データベース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 — 選定基準

サービス特徴向いている用途個人開発の推奨度
SupabasePostgreSQL、認証・ストレージ統合Webアプリ全般★★★★★
FirebaseNoSQL、Google統合モバイル、リアルタイムチャット★★★★☆
PlanetScaleMySQL、ブランチング大規模DB運用★★★☆☆
NeonサーバーレスPostgreSQLDBのみ必要な場合★★★★☆
Appwriteセルフホスト前提のBaaSセルフホスト重視★★★☆☆

結論として、個人開発でWebアプリを作るなら、2026年時点でSupabaseが最もバランスの良い選択肢です。PostgreSQLの汎用性、無料枠の大きさ、認証・ストレージの統合、 そしてNext.jsとの親和性の高さが決め手になります。

Supabase vs Firebase vs 他のBaaS比較図

Supabaseの料金プラン完全比較【2026年最新】

全プランの機能・制限を一覧で比較

Supabaseの料金プランは4つあります。個人開発では99%のケースで FreeプランまたはProプランで十分です。

Supabase公式の料金プランページ。Free($0)・Pro($25/月)・Team($599/月)・Enterpriseの4プラン
項目FreeProTeamEnterprise
月額料金$0$25$599要問い合わせ
データベース容量500MB8GB8GBカスタム
ストレージ1GB100GB100GBカスタム
月間認証ユーザー(MAU)50,000100,000100,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 ProFirebase 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アカウントでのサインアップが最も簡単です。

  1. GitHubアカウントでサインイン
  2. Supabaseへのアクセスを許可
  3. ダッシュボードが表示されれば完了

Step 2: 新規プロジェクトの作成(所要時間: 3分)

ダッシュボードから「New Project」をクリックし、以下の設定を行います。

  1. Organization: デフォルトでOK(後から変更可能)
  2. Project name: プロジェクト名(例: my-todo-app)
  3. Database Password: 強力なパスワードを設定(後で使うので必ずメモ)
  4. Region: Northeast Asia (Tokyo) を選択
  5. 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

マイグレーションを使うことで、「ダッシュボードで直接テーブルを変更したら、 開発環境と本番環境がズレてしまった」という事故を防げます。個人開発でも、初期段階からマイグレーションを使う習慣をつけることを強く推奨します。

Supabaseデータベース操作のフロー図

認証(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での設定

  1. Google Cloud ConsoleでプロジェクトのOAuth同意画面を設定
  2. 認証情報でOAuth 2.0クライアントIDを作成
  3. 承認済みリダイレクトURIに https://xxxxx.supabase.co/auth/v1/callback を追加

Step 2: Supabaseダッシュボードでの設定

  1. Authentication → Providers → Google を有効化
  2. 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種類があります。

バケットタイプアクセス制御用途例
PublicURLを知っていれば誰でもアクセス可ユーザーアバター、ブログ画像
PrivateRLSポリシーで制御請求書、個人データ

バケットの作成とファイルアップロード

-- 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ルート
バックエンドSupabaseDB + 認証 + ストレージ
ホスティング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を実行する習慣をつけましょう。

Next.js × Supabase アーキテクチャ全体図

よくある質問(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_dumppg_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を学ぶのにおすすめの学習順序は?

以下の順序で学ぶことを推奨します。

  1. SQLの基礎(SELECT, INSERT, UPDATE, DELETE, JOIN)— 3日
  2. Supabaseダッシュボード操作(テーブル作成、データ入力、SQL Editor)— 1日
  3. 認証(Auth)の実装(メール認証 → Google OAuth)— 2日
  4. RLSの理解と設定 — 1日
  5. Next.jsとの連携(CRUD、Server Components)— 3日
  6. Storageの活用(画像アップロード)— 1日
  7. 実際のアプリを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で何か作ってみたいけど、何から始めればいいか分からない」という方は、 ぜひ無料相談会にお越しください。あなたのアイデアに合わせた技術スタックと開発プランを一緒に考えます。

この記事をAIと深掘りする

要約・疑問の解消に。記事のタイトル・URL・参照元を入れた質問文が自動で入力されます。

AUTHOR

立川修平(ぶべ)

ShiftB 校長 / bubekichi inc. 代表

ShiftBを運営する株式会社bubekichiの代表。経理系SaaSの企業でエンジニアを経験後、独立・起業。複数スタートアップでリードエンジニアを務めながら、SNS発信がきっかけで2024年にShiftBを立ち上げる。現在は自社サービスも複数展開中。

RELATED ARTICLES

関連記事

COURSE

AI時代のアプリ開発コース

ShiftBのAIシフトコースは、Claude Codeで本格的なWebアプリケーションを作りながら学ぶコースです。コードを読め、セキュリティに責任を持って提案でき、要件定義などの上流工程まで担える状態を目指します。まずは無料相談会でご相談ください。