---
title: "Supabaseの使い方を徹底解説【個人開発の最強バックエンド入門】"
description: "Supabaseの使い方をゼロから解説。料金比較、データベース設計、認証実装、Next.jsとの連携まで、個人開発で必要な知識を網羅した完全ガイド。"
url: "https://shiftb.dev/articles/how-to-use-supabase"
publishedAt: "2026-04-04"
updatedAt: "2026-04-04"
author: "立川修平（ぶべ）"
category: "tools"
tags: ["Supabase", "バックエンド", "個人開発", "Next.js", "PostgreSQL", "BaaS"]
---

# 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で個人開発を始められる**構成になっています。

## 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 vs Firebase vs 他のBaaS比較図](https://shiftb.dev/images/articles/how-to-use-supabase-comparison.png)

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

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

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

![Supabase公式の料金プランページ。Free（$0）・Pro（$25/月）・Team（$599/月）・Enterpriseの4プラン](https://shiftb.dev/images/articles/how-to-use-supabase-ss-pricing.png)

| 項目 | 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は定額制のため予測可能性が高い**のが個人開発者にとって大きなメリットです。「今月の請求がいくらになるか分からない」という不安がありません。

## 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データベース操作のフロー図](https://shiftb.dev/images/articles/how-to-use-supabase-database.png)

## 認証（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();
```

## 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`を実行する習慣をつけましょう。

![Next.js × Supabase アーキテクチャ全体図](https://shiftb.dev/images/articles/how-to-use-supabase-nextjs.png)

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

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

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で何か作ってみたいけど、何から始めればいいか分からない」という方は、ぜひ無料相談会にお越しください。あなたのアイデアに合わせた技術スタックと開発プランを一緒に考えます。
