Supabase 環境構築でわかりにくかったところ

Supabase を触り始めたのだが、public スキーマを使わず api スキーマを使おうとしたらわかりにくかったところが複数あったのでメモを残す。

環境

  • Next.js 15.3.4
  • Supabase CLI 2.26.9

ローカル環境構築

基本的なガイドは公式ドキュメントを見ればよい。

https://supabase.com/docs/guides/local-development

リモートからスキーマ等の定義を持ってくる

先にリモート側でスキーマ等を作ってしまっている場合

supabase db pull --schema auth,api

これで auth, api スキーマの定義をリモートから取得してマイグレーションファイルにすることができる。
スキーマを取得しないと public スキーマなどの特定のスキーマしか取得してくれない。

ローカル環境の Data API で api スキーマに接続する

supabase/config.toml で schemas を修正する。

[api]
enabled = true
# Port to use for the API URL.
port = 54321
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
# endpoints. `public` and `graphql_public` schemas are included by default.
schemas = ["api"]

リモートだと Studio の設定画面に設定項目があるが、ローカル環境の Studio には画面上では設定できない。

ローカル環境で Auth Hook を有効にする

supabase/config.toml で auth.hook.custom_access_token を有効にする。

# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
[auth.hook.custom_access_token]
enabled = true
uri = "pg-functions://postgres/api/custom_access_token_hook"

リモートだと Studio の設定画面に設定項目があるが、ローカル環境の Studio には画面上では設定できない。

Data API 用に TypeScript の型を作成

下記で api スキーマの型を生成できる。

supabase gen types typescript --linked --schema api > src/utils/supabase/database.types.ts

スキーマを指定しないと public スキーマしか取得してくれない。

この型を読み込むには、クライアントサイドはこう。

import { createBrowserClient } from "@supabase/ssr";
import type { Database } from "./database.types";

export const createClient = () =>
  createBrowserClient<Database, "api">(
    process.env.NEXT_PUBLIC_SUPABASE_URL ?? "",
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? "",
    {
      db: {
        schema: "api",
      },
    },
  );

サーバーサイドはこう。

import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
import type { Database } from "./database.types";

export const createClient = async () => {
  const cookieStore = await cookies();

  return createServerClient<Database, "api">(
    process.env.NEXT_PUBLIC_SUPABASE_URL ?? "",
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? "",
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          } catch (_error) {
            // The `set` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
      db: {
        schema: "api",
      },
    },
  );
};

api スキーマを明示的に指定する必要がある。

以上