はじめに
こんにちは!Halです!
今回はTypeScript環境下でsupabaseを利用する手順について説明していきます。
今回は以下の環境を想定しています。
- TypeScriptがすでにインストール済み
- プロジェクト自体の環境構築が済んでいる
- パッケージマネージャーがpnpm
- supabaseにサインアップ済みでアカウントがある
- supabaseにプロジェクトがあり、テーブル作成済み
依存パッケージのインストール
はじめにsupabaseを利用するために必要なパッケージをインストールします。
ターミナルからsupabaseの操作をするためのCLI
pnpm add supabase --save-dev --allow-build=supabase
supabaseをtypescriptを利用するためのパッケージ
pnpm add @supabase/supabase-js
必要になる値の取得
supabaseを利用していく上で取得しなければいけない値が3つあります
- PROJECT_ID
- SUPABASE_URL
- SUPABASE_KEY
1. PROJECT_ID
- Supabase Dashboardにアクセス
- 使用するプロジェクトをクリック
- サイドバー一番下にある**「Project Settings」**をクリック
- 「General」タブ内の「General settings」に記載されているのがPROJECT_IDです
SUPABASE_URLとSUPABASE_KEYの取得
- 同じプロジェクトのダッシュボードで、サイドバーの 「Project Overview」 をクリック
- Connecting to your new project の部分にあるProject APIに記載されています
環境変数の設定
取得した値は.env
ファイルに保存します
VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_PROJECT_ID=your_project_id
Vite環境では環境変数にVITE_プレフィックスが必要です。
SUPABASE_PROJECT_IDはCLI操作時のみ使用するため、VITE_プレフィックスは不要です。
型情報の生成
すでにテーブルを作成済みだと思います。
TypeScript環境下でテーブルの型情報は、コードを入力する際に補完が効くようになるため重要です。
以下のコマンドを入力して、テーブルの型情報を生成します。
pnpx supabase gen types typescript --project-id "your_project_id" > src/types/database.types.ts
このコマンドは長いため、テーブル情報を変更して型定義を更新したいときに面倒です。
package.jsonのScriptプロパティに追加して簡単に呼べるようにしましょう。
pnpm add -D dotenv-cli
{
"scripts": {
"generate-types": "dotenv -e .env -- supabase gen types typescript --project-id \"$SUPABASE_PROJECT_ID\" > src/types/database.types.ts"
}
}
pn run generate-types
supabaseのクライアントを作成
supabaseのクライアントを作成するため、supabase.ts
をsrc/lib
フォルダ以下に作成する
現在、自分のフォルダ構成は以下の形になっている
tree src/
src/
├── lib
│ └── supabase.ts # supabaseのクライアント
├── main.tsx
├── routes
│ ├── index.tsx # ランディングページ
│ ├── querys.ts # データ取得・更新を行う処理をまとめたファイル
│ └── __root.tsx
├── routeTree.gen.ts
├── types
│ └── database.types.ts # supabaseのテーブル型定義ファイル
└── vite-env.d.ts
作成
クライアントの作成はcreateClient
関数に、SUPABASE_URLとSUPABASE_KEYを渡して行います。
createClient
関数にGenericで生成したテーブルの型を割り当てています。これにより、createClient
から取得できるsupabase
変数は,自分が作成したテーブルの型の情報を持つことが出来ます。
createClient
関数は第3引数以降にも渡せるOption
オブジェクトがあるため、気になる人は次のリンクよりチェックをしてください。
import { createClient } from "@supabase/supabase-js";
import type { Database } from "@/types/database.types";
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_KEY;
export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey)
supabaseの基本的なCRUD操作
データの取得(SELECT)
select()
メソッドを使用してテーブルからデータを取得します。デフォルトでは最大1,000行まで返されます。
// 全カラムを取得
const { data, error } = await supabase
.from('users')
.select()
// 特定のカラムのみ取得
const { data, error } = await supabase
.from('users')
.select('id, name, email')
// カラムに別名をつけて取得
const { data, error } = await supabase
.from('users')
.select('id, full_name:name, email')
データの挿入(INSERT)
insert()
メソッドを使用してテーブルにデータを挿入します。
const { data, error } = await supabase
.from('users')
.insert({
name: 'John Doe',
email: 'john@example.com'
})
.select() // 挿入されたデータを返す
const { data, error } = await supabase
.from('users')
.insert([
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' }
])
.select()
データの更新(UPDATE)
update()
メソッドを使用してテーブルのデータを更新します。必ずフィルター条件と組み合わせて使用してください。
const { data, error } = await supabase
.from('users')
.update({ name: 'Jane Doe' })
.eq('id', 1)
.select() // 更新されたデータを返す
データの削除(DELETE)
delete()
メソッドを使用してテーブルからデータを削除します。必ずフィルター条件と組み合わせて使用してください。
const { error } = await supabase
.from('users')
.delete()
.eq('id', 1)
const { error } = await supabase
.from('users')
.delete()
.in('id', [1, 2, 3])
アップサート(UPSERT)
upsert()
メソッドを使用して、レコードが存在しない場合は挿入、存在する場合は更新を行います。
const { data, error } = await supabase
.from('users')
.upsert({
id: 1,
name: 'Updated Name',
email: 'updated@example.com'
})
.select()
フィルターとの組み合わせ
これらの操作は様々なフィルター条件と組み合わせて使用できます。
// 名前に"Hal"を含むユーザーを取得
const { data, error } = await supabase
.from('users')
.select()
.ilike('name', '%Hal%')
// 年齢が20以上のユーザーを取得
const { data, error } = await supabase
.from('users')
.select()
.gte('age', 20)
// 複数の条件を組み合わせ
const { data, error } = await supabase
.from('users')
.select()
.eq('active', true)
.gte('created_at', '2025-09-07')
エラーハンドリングの実装
すべてのSupabase操作はerror
オブジェクトを返すため、適切なエラーハンドリングを実装しましょう。
const fetchUsers = async () => {
const { data, error } = await supabase
.from('users')
.select()
if (error) {
console.error('Error fetching users:', error.message)
throw new Error(`Failed to fetch users: ${error.message}`)
}
return data
}
パフォーマンスの考慮点
-
ページネーション: 大量のデータを扱う場合は
range()
を使用してページネーションを実装 -
必要なカラムのみ選択:
select()
で必要なカラムのみを指定してデータ転送量を削減 - インデックス: 頻繁に検索する条件にはデータベース側でインデックスを作成
const fetchUsersWithPagination = async (page: number, pageSize: number = 10) => {
const from = page * pageSize
const to = from + pageSize - 1
const { data, error, count } = await supabase
.from('users')
.select('*', { count: 'exact' })
.range(from, to)
if (error) throw error
return { data, count }
}
おわりに
今回はSupabaseのTypeScript環境でのセットアップから基本的なCRUD操作まで説明しました。
Supabaseは型安全性を保ちながら高速な開発を可能にするPostgreSQLベースのBaaSプラットフォームで、複雑なバックエンド構築を大幅に簡素化してくれる優れたツールです。
今回学んだ基本的なCRUD操作をマスターすれば、多くのWebアプリケーションの要件を満たすことができるでしょう。次のステップとして、認証機能やリアルタイム機能、Row Level Security(RLS)なども学んでみることをおすすめします。
参考
JISOUのメンバー募集中!
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼