ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-03-28中級

Antigravity × Supabase でリアルタイム対応フルスタックアプリを構築する実践ガイド

Antigravity IDE と Supabase を組み合わせて、認証・データベース・リアルタイム同期を備えたフルスタックアプリを構築する方法をステップバイステップで解説します。

antigravity435supabase7realtime4fullstack5postgresql5authentication4next.js4

取り組みの背景 — Supabase × Antigravity という選択肢

フルスタックアプリ開発において、バックエンドの構築は大きなハードルの一つです。データベース設計、認証システム、リアルタイム通信、ストレージ管理——これらを一から実装するには膨大な時間がかかります。

Supabase は「Firebase のオープンソース代替」として急速に支持を広げている BaaS(Backend as a Service)です。PostgreSQL ベースのデータベース、組み込みの認証機能、リアルタイムサブスクリプション、エッジファンクションなど、モダンなアプリ開発に必要な機能を一通り提供しています。

ここに Antigravity IDE のエージェント機能を掛け合わせると、スキーマ設計からフロントエンド実装までを AI が支援してくれるため、開発効率が飛躍的に向上します。ここではAntigravity と Supabase を使ってリアルタイム対応のタスク管理アプリを構築する流れを、ステップバイステップで解説します。

Supabase の基本構成を理解する

Supabase は以下の主要コンポーネントで構成されています。

  • PostgreSQL データベース: フルマネージドの PostgreSQL インスタンス。Row Level Security(RLS)によるきめ細かいアクセス制御が可能
  • Auth: メール・パスワード、OAuth(Google, GitHub 等)、マジックリンクに対応した認証基盤
  • Realtime: PostgreSQL の変更をリアルタイムで WebSocket 経由で配信するエンジン
  • Storage: S3 互換のファイルストレージ。画像やドキュメントのアップロードに対応
  • Edge Functions: Deno ベースのサーバーレス関数。Stripe Webhook などの処理に利用可能

Firebase との最大の違いは、標準 SQL が使える点です。NoSQL に不慣れな開発者でも直感的にデータモデリングができます。また、ベンダーロックインが少なく、将来的にセルフホスト(自前サーバー運用)への移行も容易です。

Antigravity プロジェクトのセットアップ

まず Antigravity で新しい Next.js プロジェクトを作成し、Supabase クライアントをインストールします。Antigravity のエージェントにプロンプトで依頼すると、プロジェクト構成の提案から実行まで自動で進めてくれます。

# Antigravity のエージェントに以下のプロンプトを送信
# 「Next.js 15 + TypeScript + Supabase のプロジェクトを作成して」
 
# エージェントが実行するコマンド例:
npx create-next-app@latest task-app --typescript --tailwind --app
cd task-app
 
# Supabase クライアントのインストール
npm install @supabase/supabase-js @supabase/ssr

次に、Supabase ダッシュボードでプロジェクトを作成し、API キーを .env.local に設定します。

# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY=YOUR_SERVICE_ROLE_KEY

Supabase クライアントの初期化は、サーバーコンポーネントとクライアントコンポーネントで異なるインスタンスを使い分けるのがベストプラクティスです。

// src/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!
  );
}
// src/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)
          );
        },
      },
    }
  );
}

Antigravity のエージェントに「Supabase の SSR クライアントを設定して」と伝えれば、この構成を自動で生成してくれます。Auth.js v5 を使った認証システムの構築ガイドも参考になりますが、Supabase Auth を使う場合は Supabase 組み込みの認証を活用する方がシンプルです。

データベース設計と Row Level Security

Supabase ダッシュボードの SQL エディタ、または Antigravity のエージェント経由でテーブルを作成します。今回はタスク管理アプリのスキーマを設計しましょう。

-- Supabase SQL Editor または Antigravity エージェント経由で実行
 
-- タスクテーブル
create table public.tasks (
  id uuid default gen_random_uuid() primary key,
  user_id uuid references auth.users(id) on delete cascade not null,
  title text not null,
  description text,
  status text default 'todo' check (status in ('todo', 'in_progress', 'done')),
  priority integer default 0 check (priority between 0 and 3),
  due_date timestamptz,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);
 
-- RLS(Row Level Security)を有効化
alter table public.tasks enable row level security;
 
-- ポリシー: ユーザーは自分のタスクのみ操作可能
create policy "Users can view own tasks"
  on public.tasks for select
  using (auth.uid() = user_id);
 
create policy "Users can insert own tasks"
  on public.tasks for insert
  with check (auth.uid() = user_id);
 
create policy "Users can update own tasks"
  on public.tasks for update
  using (auth.uid() = user_id);
 
create policy "Users can delete own tasks"
  on public.tasks for delete
  using (auth.uid() = user_id);
 
-- updated_at を自動更新するトリガー
create or replace function update_updated_at()
returns trigger as $$
begin
  new.updated_at = now();
  return new;
end;
$$ language plpgsql;
 
create trigger tasks_updated_at
  before update on public.tasks
  for each row execute function update_updated_at();

RLS は Supabase の最も強力な機能の一つです。サーバー側でアクセス制御ロジックを書かなくても、データベースレベルで認可ルールを強制できます。Antigravity のエージェントに「このテーブルに RLS ポリシーを追加して」と依頼すれば、テーブル構造を読み取って適切なポリシーを提案してくれます。

Supabase の型を自動生成する

TypeScript プロジェクトでは、Supabase CLI で型定義を自動生成しておくと、エージェントがより正確なコードを書いてくれます。

# Supabase CLI のインストール
npm install -D supabase
 
# 型定義の生成
npx supabase gen types typescript --project-id your-project-id > src/types/database.ts

生成された型を使うことで、クエリの戻り値に自動的に型が付きます。

// src/types/database.ts から自動生成される型の例
export type Task = Database["public"]["Tables"]["tasks"]["Row"];
export type InsertTask = Database["public"]["Tables"]["tasks"]["Insert"];
export type UpdateTask = Database["public"]["Tables"]["tasks"]["Update"];

リアルタイム同期の実装

Supabase Realtime は、PostgreSQL の変更を WebSocket 経由でクライアントに即座に配信する仕組みです。チームでのタスク共有や、複数デバイス間の同期に活用できます。

// src/hooks/useRealtimeTasks.ts
"use client";
 
import { useEffect, useState } from "react";
import { createClient } from "@/lib/supabase/client";
import type { Task } from "@/types/database";
 
export function useRealtimeTasks(userId: string) {
  const [tasks, setTasks] = useState<Task[]>([]);
  const supabase = createClient();
 
  useEffect(() => {
    // 初回データ取得
    const fetchTasks = async () => {
      const { data, error } = await supabase
        .from("tasks")
        .select("*")
        .eq("user_id", userId)
        .order("created_at", { ascending: false });
 
      if (!error && data) {
        setTasks(data);
      }
    };
 
    fetchTasks();
 
    // リアルタイムサブスクリプション
    const channel = supabase
      .channel("tasks-realtime")
      .on(
        "postgres_changes",
        {
          event: "*", // INSERT, UPDATE, DELETE を全て監視
          schema: "public",
          table: "tasks",
          filter: `user_id=eq.${userId}`,
        },
        (payload) => {
          switch (payload.eventType) {
            case "INSERT":
              setTasks((prev) => [payload.new as Task, ...prev]);
              break;
            case "UPDATE":
              setTasks((prev) =>
                prev.map((t) =>
                  t.id === (payload.new as Task).id
                    ? (payload.new as Task)
                    : t
                )
              );
              break;
            case "DELETE":
              setTasks((prev) =>
                prev.filter((t) => t.id !== payload.old.id)
              );
              break;
          }
        }
      )
      .subscribe();
 
    // クリーンアップ
    return () => {
      supabase.removeChannel(channel);
    };
  }, [userId, supabase]);
 
  return tasks;
}

Antigravity のエージェントに「タスクテーブルのリアルタイム同期フックを作成して」と指示すると、上記のようなカスタムフックを生成してくれます。ポイントは、filter パラメータで自分のタスクのみ受信対象にしている点です。これにより、不要なイベントの受信を防ぎ、パフォーマンスを最適化できます。

なお、Supabase ダッシュボードで対象テーブルの Realtime を有効にするのを忘れないでください(Database → Tables → tasks → Realtime を ON)。

認証フローの実装

Supabase Auth を使えば、メール認証と OAuth の両方を簡単に実装できます。

// src/app/auth/login/page.tsx
"use client";
 
import { useState } from "react";
import { createClient } from "@/lib/supabase/client";
import { useRouter } from "next/navigation";
 
export default function LoginPage() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const supabase = createClient();
  const router = useRouter();
 
  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError(null);
 
    const { error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
 
    if (error) {
      setError(error.message);
    } else {
      router.push("/dashboard");
      router.refresh();
    }
    setLoading(false);
  };
 
  const handleGoogleLogin = async () => {
    await supabase.auth.signInWithOAuth({
      provider: "google",
      options: {
        redirectTo: `${window.location.origin}/auth/callback`,
      },
    });
  };
 
  return (
    <form onSubmit={handleLogin}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="メールアドレス"
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="パスワード"
        required
      />
      {error && <p className="text-red-500">{error}</p>}
      <button type="submit" disabled={loading}>
        {loading ? "ログイン中..." : "ログイン"}
      </button>
      <button type="button" onClick={handleGoogleLogin}>
        Google でログイン
      </button>
    </form>
  );
}

OAuth コールバックの処理も忘れずに実装しておきましょう。

// src/app/auth/callback/route.ts
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();
    const { error } = await supabase.auth.exchangeCodeForSession(code);
    if (!error) {
      return NextResponse.redirect(`${origin}/dashboard`);
    }
  }
 
  return NextResponse.redirect(`${origin}/auth/error`);
}

よくあるエラーと対処法

Antigravity で Supabase プロジェクトを開発する際によくあるトラブルと、その解決策をまとめます。

RLS ポリシーが原因でデータが取得できない

Supabase はデフォルトで RLS が有効な場合、ポリシーが設定されていないとデータを一切返しません。Antigravity のエージェントに「tasks テーブルのデータが取得できない」と伝えると、RLS ポリシーの確認と修正を提案してくれます。

-- デバッグ: RLS を一時的に無効化して確認
-- ⚠️ 本番環境では絶対に無効化しないこと
alter table public.tasks disable row level security;

リアルタイムイベントが届かない

Supabase ダッシュボードで対象テーブルの Realtime が ON になっているか確認してください。また、RLS ポリシーが Realtime にも適用される点に注意が必要です。

環境変数が読み込めない

NEXT_PUBLIC_ プレフィックスがないとクライアント側で参照できません。SUPABASE_SERVICE_ROLE_KEY はサーバー側専用のため、プレフィックスなしが正しい設定です。

まとめ

Antigravity × Supabase の組み合わせは、フルスタックアプリ開発の新しいスタンダードになりつつあります。PostgreSQL ベースの堅牢なデータベース、組み込みの認証とリアルタイム同期、そして Antigravity エージェントの AI 支援を組み合わせることで、従来なら数日かかっていた実装を数時間で完了できます。

本記事のポイントを振り返ると、Supabase クライアントのサーバー/クライアント分離、RLS によるセキュアなデータアクセス制御、そしてリアルタイムサブスクリプションの実装が重要な柱です。

さらに本格的なプロダクション向けのセキュリティ対策やバリデーション設計を知りたい方は、Antigravity エージェントでセキュアな API バックエンドを構築するで詳しく解説しています。また、課金機能の統合を検討している方には、Antigravity × SaaS × Stripe フルスタックガイドもおすすめです。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-04-28
Antigravity で SaaS を丸ごと作る — Stripe 課金・認証・デプロイを1つのIDEで完結させる
Antigravity IDE だけで SaaS プロダクトを構築する全工程を解説します。Supabase認証、Stripe課金、Cloudflare Workersデプロイまで、IDEを離れずに完結させる実践ガイドです。
アプリ開発2026-03-17
TypeScript + Antigravity で実現する型安全フルスタック開発ガイド
Antigravity を使って TypeScript フルスタックアプリを型安全に構築する実践ガイド。Zod によるバリデーション、型推論の活用、エージェントとの協調開発まで徹底解説。
連携・プラグイン2026-04-04
Antigravity と Supabase で本番実装—Auth・RLS・Edge Functions・Realtime の要点
Antigravity と Supabase で本番アプリを組み立てる際の実装パターンをまとめました。Auth・RLS・Edge Functions・Realtime に加え、RLS を有効にした途端に遅くなる理由と直し方、個人開発における費用の分岐点まで扱います。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →