目次を表示する

Prisma v7 — なぜRustから撤退したのか、OSSの構造改革として読み解く

Prismaはなぜ Rust で始まったのか ── マルチ言語クライアントという野望

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-goprisma-client-py は一時期コミュニティプロジェクトとして存在していた。

公式ブログ「From Rust to TypeScript: A New Chapter for Prisma ORM」で、Prisma 自身がこう振り返っている(要約)。

「Rust を選んだ最大の理由は、単一のコアから複数言語のクライアントを支えられることだった。パフォーマンスや systems-level なアプローチはその副産物である」

つまり、Rust は「速いから」採用されたのではなく「言語に依存しないから」採用されたのである。この観点は v4 の撤退判断を理解する上で極めて重要なので、覚えておいてほしい。

③ 型安全な DB ドライバ群の成熟

2019〜2020 年当時、Rust エコシステムには tokio-postgresmysql_asynctiberius(SQL Server)、sqlx 前身などの非同期 DB ドライバが出揃い始めていた。一方、Node.js 側の pgmysql2 も十分に成熟していたが、全 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 撤退の伏線である

参考文献