Zenn
🌊

【React】Supabase CLI を使ってデータベース(PostgreSQL)関連を操作するやり方

2025/02/13に公開

Supabase CLI を使ってデータベース(PostgreSQL)関連の操作を行う際の概要を整理し、実際の使用パターンごとに「どのようなコマンドを使い、どんなフローになるか」の例を示します。特に、マイグレーション管理ローカル開発などでよく使われるコマンドが中心です。

1. Supabase CLI で扱う主なDB関連コマンド

  1. supabase start

    • Dockerを使って ローカル環境 (Postgres + Supabase API + Storage) を立ち上げる。
    • あくまでローカル専用。外部からはアクセスできない。
  2. supabase db pull

    • リモート(本番/ステージング) のDBスキーマを ローカル に同期して、supabase/schema.sqlsupabase/migrations/ に書き出す。
    • すでにブラウザでテーブルを作ってしまった場合、そのスキーマをローカルに取り込める。
  3. supabase db push

    • ローカルにある マイグレーション or スキーマリモート に反映する。
    • 「リモートにもローカルと同じDB構造を適用したい」ときに使う。
  4. supabase migration new <name>

    • マイグレーションの雛形となるSQLファイル or ディレクトリを supabase/migrations/ に生成する。
    • 生成されたファイルに CREATE TABLEALTER TABLE などのDDLを書く → その後 supabase db push でリモートに適用。
  5. supabase migration up / supabase migration down

    • ローカルDB または リモートDB に対して、マイグレーションを順方向 / 逆方向 に適用する。
    • 通常はローカル開発用か、あるいはCI/CDで使うことが多い。
  6. supabase seed / supabase/seed.sql

    • 初期データ(Seed)を挿入するためのSQLを実行する。
    • supabase db push 時に自動実行される設定にすることも可能。
    • ただし警告が出る場合(no seed files matched)は、seed.sql が存在しないかパターンが合っていないということ。

2. 代表的な使用パターン例

2.1 ローカル開発のみ行う場合

  • フロー:

    1. supabase init
      • ローカルに supabase/ フォルダを作り、設定ファイルを生成。
    2. supabase start
      • Dockerコンテナ上でローカルPostgres + Supabase API を起動。
    3. テーブルやスキーマを作る
      • 2パターン:
        A. ブラウザの Supabase Studio にローカルURLでアクセス(http://localhost:54323など)して GUI で作成する
        B. supabase migration new → SQLを書く → supabase migration up
    4. アプリからローカルSupabaseに接続して開発
      • .env や config で SUPABASE_URL=http://localhost:54321 (CLIのデフォルトポート) などを指定
  • ポイント:

    • DBがすべてローカルで完結するため、ネット接続不要で開発できる。
    • 実際にブラウザ版のSupabase Studioとまったく同じUIをローカルで触れるようになり、DBの中身もチェックしやすい。

2.2 リモート(本番・ステージング) をメインに使い、ローカルは使わない場合

  • フロー:

    1. ブラウザ で Supabase プロジェクトを作成(本番 or ステージング)。
    2. supabase link <project-ref>
      • 既存プロジェクトとローカルディレクトリを紐づけ。
    3. supabase db pull
      • すでに作ったテーブルがあれば、DBスキーマをローカルに取り込みsupabase/migrations/ に生成される。
    4. スキーマ変更
      • supabase migration new add_some_feature → 生成されたSQLに CREATE TABLE / ALTER TABLE などを記述。
      • その後 supabase db push でリモート(本番orステージング)DBを更新。
    5. アプリ(Next.js / Expo) 側は リモートSupabase に接続 (SUPABASE_URL, SUPABASE_ANON_KEY) して実装を進める。
  • ポイント:

    • ローカルDBを立てず、常に 「クラウド上の本番orステージングDB」 にマイグレーションを適用していく。
    • ブラウザのSupabase Studioで編集しても良いが、マイグレーション管理を使うなら CLIベース でやると履歴が残る。

2.3 ステージング環境と本番環境の切り替え

  • ステージング用 プロジェクトと 本番用 プロジェクトを分けて作るケースが多い(2つの Project Ref)。
  • 例えば1つのリポジトリで、本番用には supabase link <prod-project-ref>、ステージング用には supabase link <stg-project-ref> と設定ファイルを切り替える... という運用もできます。
    • ただし、1リポジトリに対して1つのconfig.toml が基本なので、ステージングと本番でブランチを分けるか、フォルダを分けるか、CIで supabase db push --project-ref ... のようにオプション指定するか、といった工夫が必要です。

2.4 ローカル -> ステージング -> 本番 の3段階パターン

  1. ローカル: supabase start で開発し、supabase migration new & migration up でスキーマテスト。
  2. ステージング: 変更が安定したら supabase db push (紐づけ先はステージング環境のProject Ref) で適用。データの挙動確認。
  3. 本番: 最終的にマイグレーションを 本番環境db push する。
  • ポイント
    • 実際には CI/CD (例: GitHub Actions) で supabase db push --project-ref stg_... / prod_... のように自動化することも多い。
    • 個人開発なら、1プロジェクトのみでローカル or 直接クラウドにpushするだけでもOK。

3. 注意点・ベストプラクティス

  1. マイグレーションをGitでバージョン管理

    • supabase/migrations に作られたSQLファイルを Gitにコミット しておくと、「いつ・どんなDDLが追加/変更されたか」を追跡できて便利。
    • 将来的に DBを再構築する際にも役立ちます。
  2. supabase/seed.sql やシードファイルの活用

    • テストデータの挿入や初期データ投入が必要なら、seed.sql を用意して INSERT INTO ... 文を記述。
    • supabase db push 時に自動的にシードが流し込まれる設定もできる(CLIバージョンやconfig次第)。
  3. CLI バージョンとプロジェクト設定の整合性

    • CLI と Supabase スタジオの機能が食い違うことがあるので、なるべく最新CLI を使う。
    • npm install -g supabase などでアップデート可能。
  4. リモートに反映する際の権限・パスワード

    • supabase db push では、DBのパスワード入力を求められることがある。
    • SupabaseプロジェクトのSettings > Database でパスワードを確認し、正しく入力してください(あるいは環境変数に設定)。

4. まとめ

  • ローカルで DB を立ち上げての開発 (supabase start) と、リモートプロジェクトへのマイグレーション管理 (db pull / db push) が、Supabase CLI での主な利用シーン。
  • supabase migration new でSQLファイルを作り、それをGit管理 → db push でリモート適用、という流れが本格開発でのベストプラクティスです。
  • 個人開発でも使っておくと、後から**「いつどんなスキーマが変更されたか」** を追跡しやすくなり、環境を作り直す時もスムーズ。
  • ステージング・本番の複数環境を運用する場合は、プロジェクトごとに supabase link したり、CI/CD--project-ref オプションを使ったりする形になることが多いです。

このように、Supabase CLI を活用すると、データベースの構造や初期データなどをコード化 (SQLファイル) して扱えるため、チーム開発や運用が非常にやりやすくなります。


Q&A

マイグレーションファイルの命名規則もしくは命名のベストプラクティスはありますか?

Supabaseには、特定の強制命名規則はありませんが、一般的には次のような「時系列 + 内容」を示す命名がベストプラクティスとしてよく使われます。


1. Supabase CLI でのデフォルト挙動

たとえば、supabase migration new add_comments_table のようにコマンドを打つと、下記のようなディレクトリやSQLファイルが自動生成されます(バージョンや設定により少し違いはあります):

supabase/
  └── migrations/
      ├── 20230901123456_add_comments_table/
      │   └── initial.sql
  • 自動でタイムスタンプ(YYYYMMDDHHMMSS 形式)が先頭に付与され、後ろにコマンド引数として指定した add_comments_table が付く
  • この**「タイムスタンプ + 内容」という形は、時系列の並びマイグレーションの内容**が一目でわかりやすく、ファイル衝突も減らせるため、実質的にベストプラクティスといえます。

2. 一般的なマイグレーションファイルの命名パターン

  1. タイムスタンプ+スネークケース

    • 例: 20230901123456_add_comments_table
    • Supabase CLI でもこの形式がデフォルト。
    • 日付時刻が先頭に来ることで「いつ作られたか」「マイグレーションの適用順」が明確になります。
  2. 連番+意味のある名前

    • 例: 001_create_posts_table, 002_add_comments_table, ...
    • Rails などに慣れている人は連番方式を好むこともありますが、チームメンバー複数人で同時に作成すると番号の競合が起きやすいため、タイムスタンプの方が衝突しにくいです。
  3. 日付+時刻+ISO8601など

    • 例: 2023-09-01T12.34.56_add_comments_table (ISO8601に近い表現)
    • これも可読性は高いですが、実質的な意味は YYYYMMDDHHMMSS と同じです。

3. ベストプラクティスのポイント

  1. タイムスタンプを自動で付ける

    • ファイルの並びを自然に時系列順にし、マイグレーション適用順が明確になる。
    • CI/CD など大人数開発でも衝突が起きにくい。
  2. 名前の後半は「何をするマイグレーションか」を簡潔に表す

    • 例: add_users_table, rename_title_column, create_address_index など。
    • 未来の自分やチームがぱっと見で「ああ、こういう変更ね」と分かるようにする。
  3. Supabase CLI の supabase migration new <name> を活用する

    • 上記コマンドを使うと、ほぼ自動でよい命名(タイムスタンプ+与えた引数)がつきます。
    • 自前でファイルを作るより、衝突リスクや間違いが少なくなります。

4. まとめ

  • Supabase CLI を使えば、<timestamp>_<name> 形式のディレクトリ・ファイルが生成されるため、これが実質的なベストプラクティスです。
  • マイグレーション名には変更内容を短く明瞭に書く(例: add_comments_table, alter_user_id_type)のが望ましい。
  • 連番やISO 形式などもありますが、同時に複数人が作業するときはタイムスタンプの自動生成方式が最も衝突しにくく、わかりやすいです。
supabase db pushでDBを更新するとき、どのスキーマが反映されるんですか?

結論としてsupabase db push「まだリモートに適用されていないマイグレーション(=新しいSQLファイル)」 を順番に実行し、DBスキーマを更新します。
既に実行済みのマイグレーションは再実行されないので、前回の create table などは次回以降の push では発火しません


1. supabase db push が実際に何を行うか

  • Supabase CLI は、supabase/migrations/ フォルダに作成された各マイグレーション(例: 20230911123456_create_posts_table/initial.sql)について、「このマイグレーションはリモートDBにもう適用済みかどうか」 を確認します。
  • 未適用であれば、そのSQLを順番に実行し、DBスキーマを更新。
  • 既に適用済みであれば、再度実行しないので 重複してCREATEしたりはしない ようになっています。

1.1 どこで「適用済み」かを記録しているの?

  • Supabase (Postgres) 内部に マイグレーションの履歴を記録するためのテーブル が自動的に作られており、CLI はそこを参照して、「どのバージョンのマイグレーションが既に適用されたか」を把握します。
  • そのため、一度create tableなどが実行済みのSQLは、次回以降の push ではスキップされるわけです。

2. 具体的な流れ

  1. supabase migration new create_posts_table
    • supabase/migrations/2023..._create_posts_table/initial.sql というフォルダ/ファイルが生成。
  2. そのファイルに CREATE TABLEALTER TABLE などのDDLを記述
  3. supabase db push
    • CLI が「まだ適用していないマイグレーション」があるかチェック → あれば実行し、DB を更新。
    • ここであなたの CREATE TABLE postsRLSポリシー作成, TRIGGER などが1度だけ走る。
  4. 次回以降の push
    • すでにリモートで “create_posts_table” マイグレーションは実行済みなので、もう一度同じSQLは走らない(再適用しない)。
    • 新しいマイグレーション (add_comments_table など) があるなら、それだけ実行される。

3. 「次回以降 pushをするとき、今回作った create…も発火しないの?」について

  • はい、発火しません。 既に適用されたマイグレーションはスキップされます。
  • もし「posts テーブルを削除して再作成したい」など大きな変更をしたい場合は、新しいマイグレーションファイルを作り、そこに DROP TABLE posts; / CREATE TABLE posts; などを書きます。

4. 「pushってどこまで本番に反映させるの?」

  • supabase db push のデフォルト挙動は、リンク済みのSupabaseプロジェクト(本番 or ステージング)に対して「未適用マイグレーション」をすべて実行し、直近のマイグレーションまで反映させます。
  • 過去のマイグレーションファイルも含めて 「リモートに適用されていないもの」があればすべて実行 されるイメージです。
  • 新しく追加したマイグレーションだけでなく、もし途中で何か別のファイルも未適用だったら全部まとめて反映します。

5. まとめ

  • 一度 push して適用されたマイグレーションは、次回以降再度実行されない
  • 追加のスキーマ変更をしたければ、別のマイグレーションファイル を作成し、また db push することになります。
  • 結果として、データベーススキーマの変更履歴をファイルとして積み上げていき、CLI は「まだ適用していない分」を順番に実行してDBと整合性を保つわけです。
別ブランチでDBを操作したが、それを取り込まなかった場合に整合性が崩れる時どうしたらいい?

作業ブランチ上で行ったマイグレーションを最終的に捨てることになった場合、「DBにだけ変更が反映されてしまい、mainブランチに戻ったときに整合性が崩れる」という状況が起こりがちです。
その際の対応策としては、
「そもそも作業ブランチで使うDB環境を分離する」
か、「マイグレーションを取り消す(ロールバック)作業を行う」 の2つが代表的です。以下に詳しく解説します。


1. ブランチごとに「別のDB環境」を使う(推奨)

1.1 ローカル開発環境をブランチごとに立ち上げる

  • supabase start でローカルのSupabase(Postgres + API)を起動し、ブランチ作業時には一時的なDBを使う。
  • ブランチから離れる際に supabase stop + Dockerコンテナ破棄すれば、DB変更を後に引きずらずに済みます。
  • メリット:
    • 「機能ブランチの実験的マイグレーションを、本番/ステージングDBに影響させずに試せる」
    • 「ブランチを捨てればコンテナも捨てるだけで、DBが汚れない」
  • デメリット:
    • ローカルでDockerが必要、チーム全体で設定する手間がある

1.2 テスト用の「別プロジェクト or ステージング環境」を用意

  • 本番やメインの開発環境とは別のSupabaseプロジェクトを用意しておき、ブランチごとにリンクさせる。
  • 作業が不要になったら、そのプロジェクトのDBをリセット or 放棄。
  • 大規模チームでは、ステージングephemeral environment(プレビュー用)として活用するパターンが多い。

2. マイグレーションを「取り消す」ロールバックを行う

もし既に本番/ステージングDBにマイグレーションを適用してしまった後で、「変更が不要になった」となった場合は、逆のDDLを実行するマイグレーションを作る、もしくは手動でDBを修正する手順をとります。

  1. 逆マイグレーションファイルを作る

    • 例: ブランチで create table new_feature; を作ったが不要になった → drop table new_feature; というマイグレーションを作り、supabase db push で適用し、DBから削除する。
    • 現状のSupabase CLIは「down.sql」を自動追跡しないので、「undo用のmigration」を別途書いて push する形が多いです。
  2. 手動でSQLを実行

    • Supabase Studio や psql などで、不要なテーブル・カラムをDROPする
    • ただし、この場合「どのバージョンが適用済みか」というマイグレーション履歴と食い違う可能性があるので、追加で整合性を取る必要が出る(あまり推奨されません)。
  3. DBをバックアップから戻す

    • 大がかりですが、「開発用ならDBをまるごと過去状態に巻き戻す」という手もある。
    • 本番で誤適用した場合の緊急対応策としては検討されますが、ローカルやステージングなら簡単にリセットするほうが早い場合もあります。

3. オススメのフローまとめ

  • 基本方針: 「作業ブランチで試すマイグレーションは、本番/メインと分離したDB環境で行う」のが安全。

    • ローカルコンテナ(supabase start)やブランチ専用ステージングプロジェクトなら、捨てるときにその環境ごと廃棄すれば済みます。
  • やむを得ず本番/メインDBに適用し、後から捨てるなら:

    • ロールバック専用(undo用)のマイグレーションファイルを作り、DROP/ALTER などで元に戻す。
    • 本番運用では慎重にテストした上で適用し、マイグレーション履歴にも「取り消し」の記録を残すとよいです。

4. 具体的シナリオへの対応

シナリオ: mainブランチ → work1 でマイグレーション → 破棄 → mainに戻る

  1. 次回から

    • work1ブランチ切ったら supabase start などでローカルDBを立ち上げ、そこで**supabase migration newdb push**。
    • ブランチで作ったマイグレーションはローカルだけに適用。本番/メインDBには触れない。
    • ブランチを破棄するなら supabase stop でコンテナ破棄、マイグレーションも捨てればOK。
    • mainに戻ったとき、本番DBは影響ゼロ
  2. 今すぐ対応策

    • 既に本番orメインDBにwork1のマイグレーションを適用してしまった場合:
      1. 新しいマイグレーションをmainブランチで作成し、不要なテーブルやカラムをDROPする
      2. supabase db push で適用 → DBが元の状態に戻る
      3. work1のマイグレーションファイルはGit上では破棄(マージしない)
    • これでDBの整合性が再びmainブランチと揃います。

5. まとめ

  • ベストプラクティスは「開発ブランチと本番(またはメインDB)を分離して、捨てるブランチのマイグレーションが本番に混ざらないようにする」こと。
  • 既に不要なマイグレーションをリモートDBに適用してしまったら、「逆マイグレーション」を作って手動でロールバックします。
  • Supabase CLI は down マイグレーションを自動管理してくれないので、こういったときには**「削除や元に戻す用のDDL」を書いたマイグレーション**を自分で用意するのが手早いです。

Discussion

ログインするとコメントできます