Supabaseをローカルで動かしてタスクを表示するサンプルアプリをvite+reactで表示する
TypeScript + Vite + React で Supabase を使った簡単な TODO アプリを作ってみた時の備忘録です。
ローカル環境での Supabase 起動からアプリケーション実装まで一通り試してみました。
今回作成したコードは以下のリポジトリに置いてあります。
使用したツールとバージョン(package.json)は以下のとおりです。
{
"name": "supabase-local-getting-started",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.12.1",
"dependencies": {
"@supabase/supabase-js": "^2.50.2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"supabase": "^2.26.9",
"typescript": "^5.8.3",
"vite": "^7.0.0"
}
}
Supabase のローカル環境セットアップ
Supabase CLI のインストールと初期化
まず Supabase CLI をインストールして、プロジェクトを初期化します。
初期化すると supabase/
ディレクトリが作成され、設定ファイルが生成されます。
> pnpm add supabase
> pnpm approve-builds
参考
ローカル環境の起動
Docker を使ってローカル環境を起動します。
PostgreSQL や Supabase Studio が含まれた環境が立ち上がります。
> pnpm exec supabase start
参考
起動が完了すると、以下のような出力が表示されます。
Started supabase local development setup.
API URL: http://127.0.0.1:54321
GraphQL URL: http://127.0.0.1:54321/graphql/v1
S3 Storage URL: http://127.0.0.1:54321/storage/v1/s3
DB URL: postgresql://postgres:postgres@127.0.0.1:54322/postgres
Studio URL: http://127.0.0.1:54323
Inbucket URL: http://127.0.0.1:54324
JWT secret: your-jwt-secret
anon key: your-anon-key
service_role key: your-service-role-key
S3 Access Key: your-s3-access-key
S3 Secret Key: your-s3-secret-key
S3 Region: local
Studio URL にアクセスすると、ブラウザ上でデータベースを管理できます。
マイグレーションファイルの作成
TODO テーブルを作成するためのマイグレーションファイルを生成します。
> pnpm exec supabase migration new init
Created new migration at supabase/migrations/20250628000000_init.sql
supabase/migrations/
ディレクトリに新しい SQL ファイルが作成されるので、以下の内容を記述します。
create table public.tasks (
id bigserial primary key,
title text not null,
done boolean default false,
inserted_at timestamptz default now()
);
alter table public.tasks enable row level security;
create policy "anyone can read" on public.tasks
for select using ( true );
マイグレーションの適用方法
ローカルだけを考えたときにマイグレーションを適用する方法はいくつかあります。
- reset --local
- ローカルのデータベースを全て初期化した上でマイグレーション+シードデータ(後述)を適用
- db push --local
- push はローカルではなくリモートの supabase に適用するコマンド
- --local オプションによってローカルへと適用が可能
- migration up
- 適用していない migration をローカルに適用するコマンド
pnpm exec supabase db reset --local
pnpm exec supabase db push --local
pnpm exec supabase migration up
シードデータの追加
初期データを投入するためのシードファイルを作成します。
supabase/seed.sql
ファイルを作成し、以下の内容を記述します。
supabase/seed.sql
というファイル名にしておくことにより db reset 時にローカルには適用してくれるようです。
insert into public.tasks (title, done)
values ('買い物をする', false),
('記事を書く', true),
('テストを実装する', false);
シードデータを適用するには、データベースをリセットします。
> pnpm exec supabase db reset --local
Resetting local database...
Recreating database...
Initialising schema...
Seeding globals from roles.sql...
Applying migration 20250628000000_init.sql...
NOTICE (42P06): schema "supabase_migrations" already exists, skipping
Seeding data from supabase/seed.sql...
Restarting containers...
Finished supabase db reset on branch main.
TypeScript + Vite + React アプリケーションの作成
Vite + React 製の supabase 上にある task を表示するだけのアプリケーションを作成します。
必要なものは以下の package.json のとおりです。
{
"name": "supabase-local-getting-started",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.12.1",
"dependencies": {
"@supabase/supabase-js": "^2.50.2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"supabase": "^2.26.9",
"typescript": "^5.8.3",
"vite": "^7.0.0"
}
}
Supabase クライアントの設定
src/lib/supabase.ts
ファイルを作成し、Supabase クライアントを設定します。
supabase に関する設定は環境変数から取得できるようにしています。
import { createClient } from "@supabase/supabase-js";
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseAnonKey) {
throw new Error("Supabaseの環境変数が設定されていません");
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
型定義の生成
Supabase から型定義を生成します。
> pnpm exec supabase gen types typescript --local src/types/database.types.ts
タスク一覧表示の実装
src/App.tsx
を作成し、タスクの一覧表示を行います。
import { useEffect, useState } from "react";
import { supabase } from "./lib/supabase";
import type { Database } from "./types/database.types";
type Task = Database["public"]["Tables"]["tasks"]["Row"];
function App() {
const [tasks, setTasks] = useState<Task[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
try {
setLoading(true);
const { data, error } = await supabase.from("tasks").select("*");
if (error) {
setError(error.message);
} else {
setTasks(data || []);
}
} catch (err) {
setError("予期しないエラーが発生しました");
} finally {
setLoading(false);
}
};
if (loading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error}</div>;
return (
<div>
<h1>タスク一覧</h1>
{tasks.length === 0 ? (
<p>タスクがありません</p>
) : (
<ul>
{tasks.map((task) => (
<li key={task.id}>
{task.title} - {task.done ? "完了" : "未完了"}
</li>
))}
</ul>
)}
</div>
);
}
export default App;
src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>
);
/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Supabase React App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
アプリケーションの実行
開発サーバーを起動してアプリケーションを確認します。
pnpm exec vite
ブラウザで http://localhost:5173 にアクセスすると、supabase 上に保存されたタスク一覧を表示するアプリがみれます。
まとめ
- Supabase CLI を使ってローカル環境を簡単に構築できました
- マイグレーションとシードデータで開発環境を整備できました
Supabase を使ってみようと思いローカルでの開発環境を整備してみました。
かなりカジュアルに使えるのでとても便利に感じています。
Firebase と違い postgres という RDBMS を使えるのが強みだと思っているので、なにかしらに使っていきたいなと思いました。
Discussion