GraphQL Code Generatorとは?client presetの設定とv7の変更点を実装目線で解説
GraphQL Code Generatorは、GraphQLスキーマと手元のオペレーションを読み取って、TypeScriptの型やクライアント用のコードを生成するCLIです。npm registryで2026年8月1日に確認した@graphql-codegen/cliのlatestは7.2.0(2026年7月6日公開)で、週間ダウンロードは760万を超える規模です。スキーマを直接手で写した型定義を保守する必要がなくなる一方、生成物の形はcodegen.tsの書き方で大きく変わるツールでもあります。この記事では、生成の流れ、設定ファイルの最小構成、client presetが出すもの、サーバー側の型生成、そしてv7とclient preset v6で入った破壊的変更までを実装目線で扱います。
まとめ:GraphQL Code Generatorを入れてよい条件
先に結論を置きます。TypeScriptでGraphQLのクライアントを書いていて、スキーマが自分たちの管理下にあるか少なくとも安定して取得できるなら、client presetを使った導入はほぼそのまま通ります。codegen.tsに3行書いてnpx graphql-codegenを叩けば、クエリの引数と戻り値に型が付いた状態から始められるためです。手書きの型定義とスキーマがずれて実行時に落ちる、という事故を構造的に潰せる点が最大の見返りでしょう。
逆に導入を急がないほうがよい場面が3つあります。第一に、Node 20以下から上げられない環境。v7はNode 20のサポートを落としており、Node 22以上が前提になりました。第二に、スキーマが日次で壊れるほど流動的な段階のプロジェクト。生成物が毎回入れ替わり、レビューの差分がノイズで埋まります。第三に、GraphQL自体をまだ採用していない、あるいはクライアントとサーバーを同一リポジトリで書いているケース。後者はtRPCとは?REST・GraphQL・gRPCとの違いと型安全なAPI実装で扱ったような、コード生成を介さずに型を共有する手段のほうが手数が少なく済みます。
GraphQL Code Generatorがスキーマから型を起こす仕組みと守備範囲
まず、このツールが何を入力に何を出しているのかを押さえます。ここを曖昧にしたまま設定を写経すると、生成物が期待と違ったときに切り分けられません。
スキーマとオペレーションを入力にTypeScriptの型を出力する流れ
入力は2種類あります。ひとつはスキーマで、SDLのファイルパスでも稼働中のエンドポイントのURLでも指定できます。もうひとつがオペレーション、つまりアプリ側に書いたクエリ・ミューテーション・サブスクリプションの定義。この2つを突き合わせ、指定したプラグインまたはpresetの形式で出力するのが処理の全体像です。
スキーマ側の設計思想についてはGraphQLスキーマ設計の核心原則に整理してあり、GraphQLそのものの前提を確認したい場合はGraphQLとは?REST APIとの違い・メリット・デメリットを先に読むと入力側の理解が揃います。生成器は与えられたスキーマを疑わないため、スキーマが雑なら出てくる型も雑になる、という関係は変わりません。
7.2系という版番号とnpmで配られている主要パッケージの構成
パッケージは本体と機能別に分かれています。npm registryで2026年8月1日に実測した各latestは次のとおりでした。表の先頭列では、見出しに示した共通の名前空間を省略し、各パッケージを見分ける末尾の名称だけを記載しています。版を照合する際は、見出しと先頭列をつないだ完全な名称で確認してください。
| @graphql-codegen/以下 | 版 | 役割 |
|---|---|---|
| cli | 7.2.0 | 実行本体とCLI |
| client-preset | 6.1.0 | クライアント一式の生成 |
| typescript | 6.1.0 | スキーマ由来の型 |
| typescript-operations | 6.1.2 | 操作ごとの型 |
| typescript-resolvers | 6.1.0 | サーバー側の型 |
7.2.0は2026年7月6日の公開で、peerDependenciesにgraphql@^17.0.0が加わった版です。同日時点でgraphql本体のlatestは17.0.2でした。CLIとpresetで版系列が別々に進む構造なので、CHANGELOGを追うときは両方を見る必要があります。
codegen.tsを探しに行く設定探索とjitiでの読み込み
設定ファイルの発見にはcosmiconfigが使われ、codegen.ts・codegen.js・codegen.yml・codegen.json・.graphqlrc・package.jsonのcodegenキーが候補になります。TypeScriptで書いた設定はjitiローダー経由で読み込まれ、.mtsや.ctsも通ります。
実務ではcodegen.tsを選ぶのが素直でしょう。CodegenConfig型を当てられるため、設定のtypoがエディタ上で分かります。複数の設定を使い分けたいときは--config(-c)でファイルを名指ししてください。
codegen.tsの最小構成とCLIから生成を回すまでの手順
次に、実際に動かすところまでを追います。手数は少なく、初回はウィザードに任せる手もあります。
initウィザードで入る依存パッケージと生成される初期ファイル
ゼロから始めるなら、対話式のセットアップが用意されています。
npx graphql-code-generator init
スキーマの場所、対象フレームワーク、プラグインの選択、出力先までを順に聞かれ、選んだ内容に応じた設定ファイルとnpmスクリプトが書き出されます。ウィザードが提示するパッケージを自分でインストールすれば準備完了。手で入れる場合の最小構成は、ランタイム依存のgraphqlと、開発依存の@graphql-codegen/cli・typescriptの3つです。watchモードを使う予定があるなら@parcel/watcherも足しておきます。
client presetを使うcodegen.tsの最小構成と各項目の意味
設定はプロジェクト直下に置きます。client presetを使う場合、書く項目は実質3つだけです。
import { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.tsx'],
generates: {
'./src/gql/': {
preset: 'client'
}
}
}
export default config
schemaはURLでもローカルのSDLファイルでも構いません。documentsはオペレーションを探すglobで、.tsxの中に埋め込んだ文字列も拾えます。generatesのキーが出力先で、client presetを使うときはファイル名ではなくディレクトリを末尾スラッシュ付きで指定する点に注意してください。ここをファイル名にすると生成が失敗します。
watchモードとCIで差分を検出する–checkの使い分け
開発中は--watch(-w)を付けて常駐させ、ソースを保存するたびに再生成させるのが定番の運用です。globを渡して監視対象を絞ることもできます。
graphql-codegen --config codegen.ts --watch
一方CIでは--checkを使います。これはドライラン相当の検証モードで、生成物をコミットする運用にしているとき、「生成し直すと差分が出る=生成物が古い」状態を落とせます。生成物をリポジトリに含めるかどうかは方針が分かれるところですが、含めるなら--checkのジョブをCIに必ず1本置いてください。含めないなら、ビルド前にgraphql-codegenを走らせるnpmスクリプトへ組み込む形になります。デバッグしたいときは--debug(-d)が使えます。
client presetが生成するgraphql関数と型の受け渡し
client presetは、公式が「あらゆるGraphQLクライアント向けに型安全なオペレーションを生成する既定の方法」と位置づけている出力形式です。個別のプラグインを並べる書き方より先に、こちらを検討する価値があります。
graphql関数が返すTypedDocumentNodeと型の伝わり方
生成先ディレクトリにはgraphqlという関数が出力されます。クエリ文字列をこの関数に渡すと、戻り値がTypedDocumentNodeになり、結果と変数の型が紐づいた状態でクライアントへ渡せます。
import { graphql } from './gql'
const UserQuery = graphql(`
query User($id: ID!) {
user(id: $id) { id name }
}
`)
このUserQueryをApollo ClientのuseQueryやurqlに渡せば、data.user.nameが補完され、変数にidを渡し忘れればコンパイルで落ちます。対応クライアントはReact側がApollo Client・urql・graphql-request・React Query・SWR、Vue側が@vue/apollo-composable・villus・@urql/vue。受け手の設定はApollo Clientとは?GraphQLクライアントの使い方とv4の変更点に整理してあります。
Fragment Maskingが強制するデータ依存の宣言とuseFragment
client presetの既定で有効になっているのがFragment Maskingです。フラグメントの結果をFragmentType<T>という包みに閉じ込め、useFragment()を通さないと中身へ触れないようにします。狙いは、あるコンポーネントが宣言していないフィールドを親から偶然もらって使ってしまう状態を防ぐこと。
言い換えると、コンポーネントが必要とするデータを自分のフラグメントで宣言する設計を強制する仕掛けです。フラグメントそのものの書き方はGraphQLのFragmentとは?基礎概念、役割、定義方法とメリットにまとめてあります。既存コードへ後から入れると修正箇所が広がるため、fragmentMasking: falseで一旦切って段階移行する判断もあり得ます。
Persisted Documentsでクエリを識別子へ置き換える運用
もうひとつの機能がPersisted Documentsです。クエリ本文をハッシュ化し、通信時には識別子だけを送る形にします。転送量とバンドルサイズが減るうえ、公式が「クライアントが任意のGraphQLオペレーションを送るのを防ぐ」と書いているとおり、セキュリティ面の締めにもなります。
サーバー側が識別子とクエリの対応表を持つ前提になるので、フロントだけで完結する話ではありません。documentModeをstringにしてAST生成をやめる選択肢もあり、こちらはバンドルサイズを削る方向の設定です。公開APIではなく自社アプリ専用のGraphQLサーバーなら、Persisted Documentsまで踏み込む構成を検討してよいでしょう。
サーバー側の型生成とpresetとpluginsの構成を選び分ける基準
コード生成はクライアント専用ではありません。スキーマファーストで進める場合、サーバー側の実装にも同じ仕組みが効きます。
typescriptとtypescript-operationsで分かれる出力の役割
typescriptプラグインはスキーマ由来の型、つまり各オブジェクト型やinput型、enumを出します。typescript-operationsは、書いたクエリごとの結果型と変数型を出す担当。この2つは組み合わせて使うのが基本で、片方だけでは実用になりません。
client presetは内部でこの2つ相当の処理を含んでいるため、クライアント側なら個別指定は不要です。逆に、生成物のファイル分割や命名を細かく制御したい場合はplugins方式へ降りることになります。
typescript-resolversでサーバー側の実装に型を付ける
サーバーを書くならtypescript-resolversが入ります。スキーマの各フィールドに対応するリゾルバ関数のシグネチャを型として出すため、引数の取り違えや戻り値の欠けを実装時点で潰せます。
スキーマファーストの設計では、SDLを先に固めてから型を生成し、その型に合わせてリゾルバを埋める順序になります。コードファーストのライブラリを使う場合と真逆の流れなので、チームでどちらを採るかは着手前に決めておいてください。REST側で同じ構図を経験しているなら、OpenAPI GeneratorでJavaコードを自動生成する方法で扱ったスキーマ駆動の手順と発想は共通です。
presetとpluginsをどちらで書くか決めるときの判断材料
判断は単純で、次の表の左に当てはまるならpresetを選びます。
| 状況 | 選ぶ書き方 |
|---|---|
| クライアントの新規構築 | client preset |
| 出力の粒度を制御したい | plugins指定 |
| サーバーのリゾルバ生成 | plugins指定 |
| 既存のplugins構成が稼働中 | 据え置き |
presetは複数プラグインの組み合わせに名前を付けたもの、と捉えると迷いません。既にplugins方式で動いている構成を、presetへ書き換えるだけの理由は薄いでしょう。新規に書くならpresetから入り、足りなくなった時点で降りる順序が手戻りを減らします。
v7とclient preset v6の破壊的変更と移行で詰まる箇所
ここが既存プロジェクトを上げるときの本題です。v7とclient preset v6は同じPRで入った大きな区切りで、黙って上げると型エラーが大量に出ます。
Node 22必須とESM既定になったv7の移行前チェック項目
v7.0.0の破壊的変更は3点。Node 20のサポートが落ち、Node 22以上が前提になりました。理由は依存パッケージがESM専用へ移り、Node 22のrequire()によるESM読み込みで支障がなくなったためと説明されています。
CLI本体もESM版が既定になり、コマンドの系統が整理されました。CJSが必要な場合はgraphql-codegen-cjsが残されていますが、公式は新規利用を勧めておらず将来削除の予定です。3点目がnoSilentErrors: trueの既定化で、documentsのglobに構文エラーを含むファイルがあると黙って除外せず失敗します。移行時にいきなり落ちるならこれを疑ってください。JestでESM絡みの問題が出る場合はVitestを試すよう公式が案内しています。
nullableと__typenameの生成が変わったv6の型の締まり方
client preset v6とtypescript-operations v6は、生成される型そのものを変えました。従来はnullableなフィールドが?付きの省略可能プロパティとして出ていましたが、実行時にはnullが来るだけでundefinedにはならないため、この扱いを改めています。@deferや@skip・@includeが付く場合だけが例外です。
あわせて、結果型に省略可能な__typenameを出す挙動も廃止されました。Apollo Clientのようにクライアントが自動注入する構成では、nonOptionalTypename: trueとskipTypeNameForRoot: trueで実挙動に合わせられます。カスタムスカラーの既定型もanyからunknownへ変わり、Exactユーティリティ型はtypescriptプラグインではなくtypescript-operations側が出す形になりました。いずれも型が締まる方向の変更なので、上げた直後にエラーが増えるのは想定内。CHANGELOGの該当項目と突き合わせながら潰していく作業になります。
受託案件でGraphQL Code Generatorを入れる条件と見送る場面
受託の現場で判断するなら、次の3条件が揃えば導入して問題ありません。第一に、フロントがTypeScriptで書かれていること。第二に、Node 22以上へ上げられること。第三に、スキーマの変更が週次程度のペースに収まっていること。この3つが揃うなら、初期コストは半日程度で回収できる範囲に収まります。
見送るのは、Node 20から動かせない保守案件と、スキーマがまだ日単位で入れ替わる立ち上げ初期の2つです。前者は6.x系で止める選択肢が現実的で、後者はスキーマが固まってから入れれば足ります。API開発・システム連携では、GraphQLサーバーの設計からスキーマの切り方、こうしたコード生成を含むフロント側の型運用までを一貫して受けています。既存のGraphQL APIがあり、フロントの型定義が手書きで膨らんで困っている場合は、まずdocumentsのglobがどこまで広がるかを数えるところから始めてください。
よくある質問
client presetとpluginsのどちらを使えばよいですか?
クライアント側を新規に組むならclient presetを選んでください。公式も既定の方法として案内しています。出力ファイルの分割や命名を細かく決めたい場合、あるいはサーバー側のリゾルバを生成する場合はplugins方式になります。
生成したファイルはGitにコミットすべきですか?
どちらでも運用できますが、決めたら片方に寄せてください。コミットする方針なら、CIにgraphql-codegen --checkを1本置いて生成物の陳腐化を検出します。コミットしない方針なら、ビルド前に必ず生成が走るようnpmスクリプトへ組み込みます。
Fragment Maskingは無効にできますか?
可能です。client presetのfragmentMaskingをfalseにすれば従来どおりフラグメントの結果へ直接アクセスできます。ただしコンポーネントが宣言していないデータに触れる状態も戻るため、既存コードの移行が済んだら再度有効にする前提で切るのが無難でしょう。
v6から上げると型エラーが大量に出るのはなぜですか?
client preset v6とtypescript-operations v6で、nullableフィールドの省略可能扱いと__typenameの自動付与が廃止されたためです。生成される型が実行時の挙動に近づいた結果で、出ているエラーの多くは元々あった型の緩さが表面化したものと考えてください。
Node 20のままv7を使うことはできますか?
サポート対象外です。v7.0.0でNode 20のサポートが明示的に落とされており、依存パッケージにESM専用のものが含まれます。ランタイムを上げられない案件では6.x系に固定し、上げられる時期が来てから移行する運用にしてください。