Better Auth と Drizzle を採用した Next.js Boilerplate:SaaS で長期的に正しい選択である理由

September 6, 2026
Better Auth と Drizzle ORM で構築した Next.js boilerplate が長持ちする理由。検証済みの機能、NextAuth・Prisma との公平な比較、NEXTY.DEV の配線方法を解説。
Next.js Techniques
Database

後から安く取り消せない 2 つの決断

SaaS boilerplate に入っているものの大半は交換可能です。UI キットを替える、メールプロバイダを替える、Vercel から VPS へ移す。面倒ではあっても、せいぜい一週間の仕事です。しかし 2 つだけ例外があります。認証レイヤーと ORM です。Better Auth と Drizzle を採用した Next.js boilerplate は、まさにこの 2 つに賭けています。12 か月分のプロダクトをその上に築く前に、何に賭けているのかを理解しておく価値があります。

認証の交換が高くつくのは、usersessionaccount の各テーブルがあらゆるものから参照されるからです。注文、クレジット、記事、監査ログ、チームのメンバーシップ。ORM の交換が高くつくのは、コードベース内のすべてのクエリがその ORM に向けて書かれ、マイグレーション履歴もそのツールに紐づいているからです。NEXTY.DEV はこれを一度経験しています。v3.0.0 で Supabase Auth と Supabase Database から Better Auth と Drizzle ORM に移行しました。この記事が存在する理由はそこにあります。切り替えのコストを知っており、なぜ戻らないのかも知っているからです。

Better Auth が SaaS boilerplate にもたらすもの

Better Auth は自らを、TypeScript のためのフレームワーク非依存で汎用的な認証・認可フレームワークと位置づけています。コアはメール/パスワードとソーシャルログインを提供し、それ以外はすべてプラグインです。SaaS が実際に必要とする部分を、公式ドキュメントで検証した範囲で挙げます。

  • Magic link:ユーザーのメールにリンクを送信し、クリックすれば認証完了。パスワード不要。
  • Email OTP:メールアドレスに送るワンタイムコード。サインイン、メール確認、パスワードリセットに使用可能。
  • Google One Tap:Google の One Tap API によるワンタップログイン。クライアント側とサーバー側の処理をプラグインが担当。
  • 二要素認証:認証アプリの TOTP、メールまたは電話の OTP、復旧用バックアップコード、信頼済みデバイス。
  • Organization:組織、メンバー、有効期限付きのメール招待、3 つのデフォルトロール(owner、admin、member)、カスタムロール、チーム、拡張可能なアクセス制御。
  • Admin:ユーザー作成、ロール変更、BAN と解除(一時的または永久)、なりすましログイン、ユーザー一覧、セッション失効。

その根底にある設計原則は「認証はあなたのコードベースの中に住む」です。Better Auth はあなたが所有する 4 つのコアテーブル(user、session、account、verification)と、有効化したプラグインが追加するテーブルに書き込み、npx auth@latest generate であなたの ORM 向けのスキーマを生成します。

何を置き換えるのか、そして公平なトレードオフ

NextAuth / Auth.js。 Auth.js は成熟したランタイム非依存のライブラリで、100 以上の OAuth プロバイダと、Prisma、Drizzle、Supabase、Kysely などのアダプタを備え、OAuth、magic link、credentials、WebAuthn をサポートしています。両者の差は SaaS 固有レイヤーの深さです。Auth.js が提供するのは session と user であり、組織、ロール、BAN、2FA、なりすましは自分で作ることになります。もう一つの実務的な違いはセッション戦略です。Auth.js はデータベースアダプタを設定しない限り JWT session がデフォルトで、公式ドキュメント自身が「エンコードされた有効期限より前に JWT を失効させることは不可能」であり、サーバー側のブロックリストが必要だと率直に述べています。一方でデータベース session は「いつでもサーバー側で変更できる」代わりに、データベースへの往復が発生します。Better Auth はデフォルトでデータベース session です。SaaS の管理者がユーザーを BAN して即座に効かせたいとき、必要なのはこちらです。

ホスト型認証(Supabase Auth、Clerk、Auth0)。 ホスト型プロバイダを選ぶ正当な理由は、運用を他人が担ってくれることです。パスワードハッシュ、OAuth コールバックのエッジケース、メール到達率、そしてサポートチームが初日から使える管理画面。その代償として、ユーザーの識別情報は他人のスキーマと他人の料金プランの中に置かれ、ユーザーに触れるプロダクト機能はすべて余分なネットワークホップを挟むか、シャドウコピーを維持することになります。Better Auth なら user テーブルはあなたの Postgres 内の普通のテーブルで、orderscredit_transactions と一つのクエリで join できます。すでにデータベースを運用している小さなチームにとって、これはインフラが増えるのではなく減る話です。

具体的に SaaS に必要なのは、ソーシャルログイン、パスワード嫌いのためのパスワードレス経路、管理画面のためのロール、セッションを即座に切る能力、そしていずれ必要になるチーム機能です。Better Auth はコードベースを離れることなくこの 5 つを網羅します。

Drizzle ORM が SaaS boilerplate にもたらすもの

Drizzle 自身の売り文句は「SQL を知っていれば Drizzle を知っている」です。依存関係ゼロの TypeScript ORM で、約 31 KB、serverless-ready by design を掲げ、PostgreSQL、MySQL、SQLite などの標準ドライバ上で動作します。スキーマは TypeScript、クエリビルダは SQL をなぞり、リレーショナルクエリ API は正確に 1 本の SQL にコンパイルされます。マイグレーションは drizzle-kit が担当し、drizzle-kit generate がスキーマと前回のスナップショットを diff して SQL を書き出し、drizzle-kit migrate がそれを適用します。

テーブル 1 つとクエリ 1 つ。凝ったものは何もありません。

import { pgSchema, text, timestamp, integer, uuid } from 'drizzle-orm/pg-core'
import { eq, desc } from 'drizzle-orm'

// プロジェクトごとに Postgres schema を 1 つ持てば、複数アプリで 1 つのデータベースを共有できる
export const app = pgSchema('myapp')

export const orders = app.table('orders', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: text('user_id').notNull(),
  amountCents: integer('amount_cents').notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
})

// 完全に型付け済み:{ id: string; userId: string; amountCents: number; createdAt: Date }[] が返る
const recent = await db
  .select()
  .from(orders)
  .where(eq(orders.userId, session.user.id))
  .orderBy(desc(orders.createdAt))
  .limit(20)

SaaS における Drizzle vs Prisma

Prisma はもう一つの本格的な選択肢であり、良い選択肢です。独自の宣言的スキーマ言語、自動生成される型安全なクライアント、Prisma Migrate、Prisma Studio を持ち、ドキュメントには Prisma Client がサーバーレスを含むサポート対象の Node.js/TypeScript バックエンドで動作すると明記されています。Prisma のランタイムはこの 2 年で大きく変わったので、エンジンのバイナリを軸にした古い比較記事を読んだなら、決める前に対象ランタイムについて prisma.io で再確認してください。

日々の作業で実際に効いてくる違いは哲学です。Prisma は SQL を独自のクエリ言語とスキーマファイルの背後に隠します。Drizzle は SQL から一歩の距離に留まり、スキーマは素の TypeScript なので、テーブルを定義するファイルがそのまま型をエクスポートし、言語を離れずにインデックス、部分インデックス、ON DELETE のセマンティクスまで書けます。シーケンス列と next_grant_at の部分インデックスを持つ credit_transactions 台帳を書くことになる SaaS では、SQL に近いことはスタイルの好みではなく実務上の要件になります。

なぜこの 2 つは相性が良いのか

どちらも TypeScript ファーストです。どちらもデータをあなたのデータベースに置き、間にベンダーを挟みません。そして Better Auth には公式の Drizzle アダプタがあります。drizzleAdapter(db, { provider: 'pg' })schema オプションを渡して、Better Auth のモデルを Drizzle のテーブルにマッピングします。アダプタはテーブル名の一致を求め、CLI が Drizzle スキーマを生成してくれるので、認証テーブルは課金テーブルと同じ schema.ts に並ぶ普通の行になります。マイグレーション履歴は一つ、型は一組、見る場所は一か所です。

NEXTY.DEV は Better Auth と Drizzle をどう配線しているか

NEXTY.DEV は Next.js SaaS boilerplate であり、v3.0.0 以来この組み合わせを本番で運用しています。changelog によれば、Supabase Auth から離れた理由はより高い柔軟性、Supabase Database から Drizzle に移った理由はより良い開発体験。どちらも今のところ裏切られていません。

認証方式。 Google と GitHub の OAuth、email OTP と magic link。フォームには Cloudflare Turnstile、ログインには IP 単位とユーザー単位のレート制限。Better Auth の admin プラグインが管理画面を支えます。ユーザーロール、BAN(BAN されたユーザーのセッションも同時にクリア)、流入元付きのユーザー一覧。チームが必要になれば organization プラグインを同じ設定に差し込むだけで、nexty.dev 自身がシート上限付きのチーム招待にこれを使っています。サーバー側には小さなガード(getSessionisAdmin)があり、保護ページや server action がセッションチェックを再実装する必要はありません。生成が必要な秘密鍵は BETTER_AUTH_SECRET だけで、Better Auth secret ジェネレーターがブラウザ内で生成します。

データベース。 DATABASE_URL を入れるだけで、接続ファクトリがプラットフォームとプロバイダに応じてプール設定を選びます。Supabase、Neon、セルフホストの Postgres に対応。Supabase の pooled 接続では prepared statements が自動的に無効化されます。transaction モードの PgBouncer は、そうしないと静かに失敗するので、これは重要です。認証テーブルを含むすべてのテーブルが一つの schema.ts と一つの drizzle-kit マイグレーションディレクトリに収まります。

スキーマ分離。 すべてのテーブルは public ではなく pgSchema('nexty') の下に宣言されます。複数のプロジェクトがテーブル名の衝突なしに一つの Postgres インスタンスを共有でき、プロジェクトのデータベース間移動は外科手術ではなく schema dump 一回で済みます。完全な手順はデータベースのスキーマ分離とマイグレーションを参照してください。

SaaS の残りの部分。 Stripe(および Creem、PayPal)でサブスクリプション、買い切り、クレジット台帳。next-intl で en、zh、ja が最初から利用可能。多言語記事対応の CMS。Resend または Cloudflare Email Sending。R2 ファイルストレージ。AI SDK のデモ。Pro ライセンスは買い切り $188、生涯アップデート付きで、プライベートなソースリポジトリへのアクセスが得られます。オープンソース版は無料で機能を絞ったスターターで、i18n、ニュースレター、アナリティクス、静的ブログを含みますが、データベース、認証、決済は含まれません。詳細は料金紹介ドキュメントへ。

すでに Supabase Auth や NextAuth を使っているチームへの移行メモ

現実的に言えば、これはデータ移行とコード移行の両方であり、データの方が簡単な半分です。

Supabase Auth から。 auth.users と identities をエクスポートし、Better Auth の useraccount テーブルに挿入します(リンク済みプロバイダごとに account を 1 行)。問題はパスワードハッシュです。Supabase は bcrypt を保存し、Better Auth のデフォルトは scrypt です。Better Auth のパスワードハッシュを旧形式を検証できるよう設定するか、初回ログイン時に magic link でリセットを強制するかのどちらかになります。session は移行しません。全員が再ログインします。最も時間を見込むべきは supabase.auth.getUser() の呼び出しと RLS 依存クエリの置き換えです。Drizzle は Postgres に直接話しかけるため、auth.uid() を鍵にした RLS ポリシーはもう効きません。

NextAuth / Auth.js から。 テーブル形状は近い(user、account、session、verification token)ので、列マッピングのスクリプトで大半をカバーできます。JWT session を使っていたなら移行するものはなく、ユーザーが再認証するだけです。大きいのはコードのコストで、すべての getServerSessionuseSession が Better Auth の呼び出しに変わり、後付けしたロールロジックは admin プラグインの role フィールドに置き換わります。

いずれの場合も。 まず別の Postgres schema で新しい認証を動かし、コピーを移行して、件数を突き合わせてから DNS を切り替えてください。典型的な SaaS で 2 日から 5 日の仕事であり、午後一つで終わるものではありません。

FAQ

NextAuth と比べて Better Auth は本番で使えますか

どちらも本番で使われています。Auth.js は歴史が長くプロバイダ一覧も広い。Better Auth は組み込みの SaaS レイヤー(組織、admin、2FA、BAN)が深く、デフォルトでデータベース session です。何を自分で所有し、何を自分で作りたいかで選んでください。

Drizzle はセルフホストの Postgres 専用ですか。Supabase や Neon でも使えますか

3 つとも使えます。Drizzle は標準の Postgres ドライバ上で動きます。プロバイダ固有の唯一の細部は Supabase の pooled 接続文字列で、prepared statements の無効化が必要です。NEXTY.DEV はこれを代わりに行います。

Better Auth と Drizzle の boilerplate はサーバーレスや Cloudflare Workers で動きますか

Drizzle は serverless-ready by design、Better Auth はフレームワーク非依存です。NEXTY.DEV は Vercel、Cloudflare Workers、Dokploy、Coolify にデプロイでき、Workers 経路ではデータベース接続に HTTP ドライバか Hyperdrive を使います。

ライセンス形態は何ですか

Pro は買い切り $188、生涯アップデート付きです。プライベートリポジトリのコラボレーターとして招待され、将来のバージョンにもアクセスし続けられます。

おわりに

2026 年に SaaS を始めるなら、そしてユーザーの識別情報とデータを自分の Postgres に置き、型がスキーマからクエリ、セッションまでついてくる状態を望むなら、Better Auth と Drizzle はもう一度選び直しても同じ組み合わせです。NEXTY.DEV はその選択に、決済、i18n、CMS、管理画面を配線済みの状態で同梱しています。紹介を読み、プランを比較して、後から引き剥がさなくて済むスキーマから始めてください。