Prisma ORM を導入したら型安全なDB操作がかなり楽になった話

TypeScriptプロジェクトにPrisma ORMを導入した体験談。スキーマから型が自動生成される仕組みや、マイグレーション管理がどう変わったかをまとめます。

🙌 結論から

TypeScript プロジェクトに Prisma ORM を導入したら、DBアクセスの型安全さがかなり上がって、コードへの信頼度が段違いに変わったと感じています!

スキーマファイル(schema.prisma)にテーブル定義を書くだけで TypeScript の型と DB クライアントが自動生成されます。

生 SQL を書いたり as User でキャストしたりする必要がなくなって、エディタの補完がしっかり働く状態で DB 操作ができるのが、実際に仕事で使ってみた最大の収穫です。

💡 導入前の状況

以前は MySQL + mysql2 ライブラリを直接使っていて、クエリ結果を as User[] のようにキャストしていました。

const [rows] = await connection.query('SELECT * FROM users WHERE id = ?', [id])
const user = rows[0] as User

これの何が困るかというと、DBのカラム名を変えても TypeScript 側がエラーを出さない点です(・_・;)

カラム名のスペルミスも実行して初めて気づく、という状況で、変更が入るたびに影響箇所の洗い出しに時間がかかっていました。

型がついているはずなのに、実行時に undefined になる事故が何度か起きて「これは根本から変えた方がいい」と思ったのが Prisma を試したきっかけです。

👀 Prismaのセットアップ

インストールはシンプルです。

npm install prisma @prisma/client
npx prisma init

prisma/schema.prisma というファイルが生成されるので、ここにデータソースとモデルを定義します。

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  createdAt DateTime @default(now())
}

定義が終わったら npx prisma generate を実行すると TypeScript のクライアントが自動生成されます!

初回の設定はここまでで、あとは既存テーブルがある場合は npx prisma db pull でスキーマを逆生成できます。

✨ スキーマと型の自動生成

Prisma の一番の強みは、スキーマから TypeScript の型が自動生成される点です。

@prisma/client をインポートするだけで、型付きの DB クライアントが使えます。

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

// user の型は自動で User | null になる
const user = await prisma.user.findUnique({
  where: { id: 1 },
})

user.nameuser.email にはエディタの補完がきちんと働いて、存在しないカラムを参照しようとすると コンパイル時にエラーになるのがかなりありがたいです(^o^)/

マイグレーションも npx prisma migrate dev で管理できるため、SQL ファイルを手で書く必要がなくなりました。

👍 実際に使ってみた感想

一番ありがたかったのは、テーブル構造を変えたときに型エラーですぐ気づけることです!

以前はカラムを追加したときにアプリ側の修正漏れが発生しがちでしたが、Prisma を導入してからは npx prisma generate を実行するだけで型が更新されて、影響箇所がすぐわかるようになりました。

一点だけ気をつけたいのは、prisma.user.findMany() で大量データを取得するときのパフォーマンスです(^^;)

必要なカラムだけを select で絞る書き方に慣れておくと、本番環境でも安心です。

const users = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
  },
})

ネストした関連テーブルを一緒に取得したいときは include を使うと、JOIN 相当のことが型安全にできます。

🔍 Typed SQLで生SQLも型安全に書く

Prisma を使っていても、複雑な集計クエリなどではどうしても生 SQL を書きたくなる場面があります。

以前は $queryRaw を使っていたんですが、これだと戻り値の型が any 寄りになってしまって、Prisma を導入した意味が半減してしまうのが悩みでした(・_・;)

そこで使い始めたのが Typed SQL という機能です。

.sql ファイルにクエリを書いておくと、Prisma がそのクエリの戻り値に対応した TypeScript の型を自動生成してくれます。

-- prisma/sql/getActiveUsers.sql
SELECT id, name, email FROM User WHERE createdAt > $1
import { getActiveUsers } from '@prisma/client/sql'

// 戻り値の型も自動でついてくる
const users = await prisma.$queryRawTyped(getActiveUsers(since))

複雑な集計や、ORMの書き方では表現しづらいクエリを書くときも、型の恩恵を手放さずに済むようになったのがかなりありがたいです(^^)

ちなみに Prisma は2025年11月にリリースされた Prisma 7 で、内部のRustで書かれたクエリエンジンを廃止して、フルTypeScript/WASMランタイムに移行しています。

これによってクライアントのバンドルサイズがかなり軽くなり、コールドスタートも速くなったそうで、Edge環境(Cloudflare Workersなど)でも動かしやすくなりました。

私が最初に紹介したセットアップは基本的にそのまま動きますが、最新版だと datasource の設定に加えてドライバーアダプター(@prisma/adapter-pg など)を明示的に指定するのが必須になっている点は、新しくプロジェクトを始める方は覚えておくとよさそうです。

パパ系Webエンジニア〜愛用ガジェット一覧 🛍️

この記事を書いている作業環境のガジェットを楽天ROOMにまとめています ✨ 在宅エンジニアのデスク作りの参考にどうぞ 🙌

🙌 まとめ

Prisma ORM は TypeScript との相性が本当によくて、型安全さと DB 操作のしやすさが同時に手に入るのが魅力です!

生 SQL や as キャストをたくさん書いている TypeScript プロジェクトがあれば、境界部分から少しずつ Prisma に置き換えてみると、コードへの信頼度がかなり上がります(`・ω・´)

マイグレーションの管理もコマンド一発で完結するので、チーム開発でも扱いやすいです。

まずは小さなプロジェクトで試してみるのが、感覚を掴む一番の近道だと思います。

※ Prisma のアーキテクチャやAPIは今も活発に更新されています。最新情報は Prisma公式ドキュメント をご確認ください👀