Prismaはなぜ Rust で始まったのか ── マルチ言語クライアントという野望
v7 の Rust 撤退を理解するには、まず「なぜ Rust を採用したのか」を押さえる必要がある。2018〜2019 年、その選択は極めて合理的だった。本章では、Prisma 2(現 Prisma ORM)設計時の判断を、当時の文脈で再構成する。
Prisma の前史 ── GraphCool という出発点
Prisma Inc. のルーツは 2016 年頃の GraphCool である。GraphCool は「GraphQL バックエンドを自動生成する BaaS」として始まった。ここで作られた基盤が、後に Prisma 1(2018 年)となり、さらに現在の Prisma ORM(Prisma 2、2020 年 GA)に受け継がれていく。
timeline
title Prisma の系譜
2016 : GraphCool(GraphQL BaaS)
2018 : Prisma 1(GraphQL ゲートウェイ)
2020 : Prisma 2 GA(現 Prisma ORM)
Rust 製 Query Engine 導入
2024 : ORM Manifesto 公開
2025 : Rust-free Early Access
2025 : Rust-free GA(v6.16)
2025 : Prisma 7.0 — Rust-free デフォルト
Prisma 1 時代、クライアント(Node.js アプリ)は Scala 製のサーバー(Prisma Server)を経由して DB にアクセスしていた。この構成は柔軟だった反面、運用コストが高かった。v2 設計時の論点は「このバックエンドの複雑性を、どうやって開発者から隠すか」だった。
Prisma 2 の基本アーキテクチャ
Prisma 2(2020 年 GA)が採ったのが、Query Engine と呼ばれる独立プロセスの同梱である。
graph LR
A[Node.js アプリ] -->|stdin/stdout or HTTP| B[Query Engine<br/>Rust バイナリ]
B -->|libpq / tiberius / etc.| C[(PostgreSQL / MySQL / SQLite / ...)]
style B fill:#ff9,stroke:#333
prisma generate すると…
node_modules/.prisma/client/
├── index.js (TypeScript/JS のクライアントコード)
├── query-engine-darwin-arm64 (← Rust バイナリ。OS ごとに別物)
├── query-engine-debian-openssl-3.0.x (← これも Rust バイナリ)
└── query-engine-rhel-openssl-1.0.x (← OpenSSL バージョンごとにさらに)
ユーザーが prisma.user.findMany({ where: { ... } }) を呼ぶと、内部では Node.js プロセスが子プロセス(またはライブラリとしてリンクされた Rust コード)にクエリ記述を送り、Rust 側で SQL を生成し、DB に問い合わせ、結果を受け取って Node.js に返す。
この設計の当時の利点は明快だった。
Rust を採用した 4 つの合理性(2019〜2020 年時点)
① パフォーマンスとメモリ制御
SQL 生成、結果バインディング、コネクションプール管理は CPU/メモリ集約的である。V8 の GC に任せるより、Rust の所有権モデルで明示的にライフタイムを制御した方が、予測可能なスループットが出る。当時の Node.js は Worker Threads もまだ実用化前で、シングルスレッドのイベントループから重い処理を追い出す手段として「ネイティブバイナリ」は合理的な選択だった。
② マルチ言語クライアント戦略(これが最重要)
Prisma の当初のビジョンは「ORM を TypeScript だけに提供するのではなく、Go、Python、Scala、Rust 向けにも展開する」ことだった。この戦略にとって、Query Engine が 言語非依存の独立バイナリ であることは必須条件だった。
graph TD
subgraph "想定していた未来(2019〜2020)"
TS[TypeScript Client]
GO[Go Client]
PY[Python Client]
SC[Scala Client]
RS[Rust Client]
end
TS --> QE[Query Engine<br/>Rust バイナリ]
GO --> QE
PY --> QE
SC --> QE
RS --> QE
QE --> DB[(Database)]
ロジック(SQL 生成、プラン最適化、結果マッピング)を Rust に集約しておけば、あとは各言語向けに薄いクライアントを書くだけで ORM を展開できる、という構想である。実際、prisma-client-go、prisma-client-py は一時期コミュニティプロジェクトとして存在していた。
公式ブログ「From Rust to TypeScript: A New Chapter for Prisma ORM」で、Prisma 自身がこう振り返っている(要約)。
「Rust を選んだ最大の理由は、単一のコアから複数言語のクライアントを支えられることだった。パフォーマンスや systems-level なアプローチはその副産物である」
つまり、Rust は「速いから」採用されたのではなく「言語に依存しないから」採用されたのである。この観点は v4 の撤退判断を理解する上で極めて重要なので、覚えておいてほしい。
③ 型安全な DB ドライバ群の成熟
2019〜2020 年当時、Rust エコシステムには tokio-postgres、mysql_async、tiberius(SQL Server)、sqlx 前身などの非同期 DB ドライバが出揃い始めていた。一方、Node.js 側の pg、mysql2 も十分に成熟していたが、全 DB に一貫した非同期抽象を持たせるなら Rust の方がやりやすかった。
④ Query Plan のキャッシュと最適化
Prisma のクエリエンジンは、Prisma Query(findMany({ include: { ... } }) のような DSL)を SQL 群に変換する際、結合戦略の選択や N+1 を避けるサブクエリ生成などを行う。この種の最適化はコンパイラ的な設計と相性が良く、当時の社内知見(GraphCool の Scala 実装経験)と Rust の表現力が噛み合った。
ここまでで見えてくること
2019〜2020 年の時点で、Rust 採用には「少なくとも四つの合理性」があった。どれも嘘ではなかった。しかし、次の三つの前提が静かに変質していった。
前提① 「マルチ言語クライアント戦略を続ける」
→ 実際には TypeScript ユーザーが 95% 以上を占め、
他言語クライアントは伸び悩んだ
前提② 「Rust の速度がアプリ側に届く」
→ 現実は Node.js ⇔ Rust のシリアライズ/デシリアライズが
支配的で、肝心の Rust の速度が相殺された
前提③ 「サーバーレス / エッジは例外ケース」
→ Cloudflare Workers、Vercel Edge、Deno Deploy、Bun が
メインストリームになり、ネイティブバイナリが動かない
ランタイムが「少数派」ではなくなった
この三つの前提が崩れたとき、「Rust で集約されたコア」は長所ではなく負債に反転した。次章では、v6 までの数年間に何が詰まっていったのか ── Prisma チーム自身が 2024 年 12 月の「ORM Manifesto」で告白した四つの負債を見ていく。
本章のまとめ
✅ Prisma の Rust 採用(2020 GA)は「速さ」ではなく
「マルチ言語クライアント戦略」が主動機だった
✅ 独立プロセスの Query Engine は、2020 年時点では
パフォーマンス・型安全・言語非依存の三つを同時に達成する妥当解だった
✅ しかし「前提」が変質した:
- TypeScript ユーザーへの集中
- クロス言語通信のオーバーヘッド
- エッジランタイムのメインストリーム化
✅ この前提の変質が、v7 の Rust 撤退の伏線である