1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Supabase + TypeScript】SupabaseセットアップからCRUD操作まで

Posted at

はじめに

こんにちは!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つあります

  1. PROJECT_ID
  2. SUPABASE_URL
  3. SUPABASE_KEY

1. PROJECT_ID

  1. Supabase Dashboardにアクセス
  2. 使用するプロジェクトをクリック
  3. サイドバー一番下にある**「Project Settings」**をクリック
  4. 「General」タブ内の「General settings」に記載されているのがPROJECT_IDです

プロジェクトID

SUPABASE_URLとSUPABASE_KEYの取得

  1. 同じプロジェクトのダッシュボードで、サイドバーの 「Project Overview」 をクリック
  2. Connecting to your new project の部分にあるProject APIに記載されています

スクリーンショット 2025-09-06 211450.png

環境変数の設定

取得した値は.envファイルに保存します

.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プロパティに追加して簡単に呼べるようにしましょう。

package.jsonで.envを参照するために必要なパッケージをインストール
pnpm add -D dotenv-cli
package.jsonに型生成スクリプトを追加
{
  "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.tssrc/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_URLSUPABASE_KEYを渡して行います。

createClient関数にGenericで生成したテーブルの型を割り当てています。これにより、createClientから取得できるsupabase変数は,自分が作成したテーブルの型の情報を持つことが出来ます。

createClient関数は第3引数以降にも渡せるOptionオブジェクトがあるため、気になる人は次のリンクよりチェックをしてください。

supabase.ts
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では、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてくださ!
▼▼▼

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?