Migrating from GraphQL Code Generator
GraphQL Code Generator is a great tool for generating code from GraphQL schema and operations. Basically it has the same goal as nitrogql. This page guides you how to migrate from GraphQL Code Generator to nitrogql.
GraphQL Code Generator has a couple of presets that control how TypeScript code is generated. nitrogql's approach is similar to the near-operation-file preset. This preset was the recommended preset while GraphQL Code Generator was in v2.
While GraphQL Code Generator has changed their recommended preset to the client preset, nitrogql still endorses the idea of the near-operation-file preset.
๐ nitrogql supports code generation for both client-side TypeScript code (code that uses GraphQL clients) and server-side TypeScript code (code that implements GraphQL resolvers). This guide covers migration of both client-side and server-side code.
Prerequisites
This guide assumes that you are using GraphQL Code Generator under the following conditions:
- You are using the near-operation-file preset for client-side code generation.
- You write your GraphQL operations in
.graphql
files, not inside.ts
files.
If you diverge from these conditions, you need to first migrate to these conditions before migrating to nitrogql.
Before migrating to nitrogql
Apart from the above fundamental differences, nitrogql has limited, opinionated set of configuration options. This means that some of the configuration options you used in GraphQL Code Generator may not be available in nitrogql.
We recommend you to first adjust your GraphQL Code Generator configuration to be compatible with nitrogql as much as possible. This will make the migration process easier.
Use TypedDocumentNode
GraphQL Code Generator has a couple of plugins that generate TypeScript code from GraphQL operations. For example, typescript-react-apollo
generates React Hooks for each GraphQL operation which use Apollo Client under the hood.
However, nitrogql only supports TypedDocumentNode
-based code generation. Don't worry, TypedDocumentNode can be used with any popular UI library or GraphQL client library. That's why GraphQL Code Generator also recommends using TypedDocumentNode.
Therefore, you need to migrate to the typed-document-node
plugin. If you are not familiar with TypedDocumentNode, Episode #41 of graphql.wtf is a great resource to learn how to migrate to typed-document-node
.
Before you can migrate to nitrogql, you need to be using only typescript-operations
and typed-document-node
plugins for client-side code, not those library-specific ones.
Regarding server-side code (if any), you should be using the typescript-resolvers
plugin.
Disable case conversion
Under the default settings, GraphQL Code Generator converts identifiers to PascalCase. For example, getUser
is converted to GetUser
and ENUM_VALUE
is converted to EnumValue
.
nitrogql does not do such case conversion by default. Therefore, the namingConvention
option of the typescript-operations
plugin should be set to keep
. If you change the namingConvention
option, you may also need to change TypeScript code accordingly.
# codegen.yml
config:
namingConvention: keep
Set enumsAsConst: true
GraphQL Code Generator generates code from enums using TypeScript's enum
syntax by default. However, nitrogql does not use that syntax. Instead, nitrogql uses plain union types.
This difference is not a big deal, but it may cause some incompatibility issues. Therefore, it is recommended to set enumsAsConst: true
and solve any incompatibility issues before migrating to nitrogql.
# codegen.yml
config:
enumsAsConst: true
Change output extension
By default, the near-operation-file preset generates foo.generated.ts
next to foo.graphql
. This means that if you want to import code generated from foo.graphql
, you need to import foo.generated.ts
:
// default setting of GraphQL Code Generator
import { fooQuery } from "./foo.generated";
On the other hand, nitrogql recommends to import directly from foo.graphql
:
// after migrating to nitrogql
import { fooQuery } from "./foo.graphql";
For the ease of migration, adjust GraphQL Code Generator's configuration to generate foo.graphql.ts
instead of foo.generated.ts
. This can be done by setting extension: .graphql.ts
in presetConfig
.
After you change the extension, you need to update all import declarations to import from .graphql
files instead of .generated
files. Don't forget to update your.gitignore
to ignore .graphql.ts
files.
# codegen.yml
generates:
src/:
# ...
presetConfig:
extension: .graphql.ts
Adjust generated type names
GraphQL Code Generator and nitrogql have different naming conventions for generated types. Before migrating to nitrogql, adjust your code to match nitrogql's naming convention.
For example, when you have a query named GetUser
, default output of GraphQL Code Generator and nitrogql are summarized as follows:
GraphQL Code Generator | nitrogql | |
---|---|---|
operation document object | GetUserDocument | GetUserQuery |
operation result type | GetUserQuery | GetUserResult |
operation variables type | GetUserQueryVariables | GetUserVariables |
Note that Query
in the table is substituted with Mutation
or Subscription
depending on the operation type.
You can adjust the names of result type and variables type with the following settings:
# GraphQL Code Generator config
config:
omitOperationSuffix: true
operationResultSuffix: Result
As is the case with other configuration changes, you need to update all TypeScript code that imports these types.
GraphQL Code Generator (adjusted) | nitrogql | |
---|---|---|
operation document object | GetUserDocument | GetUserQuery |
operation result type | GetUserResult | GetUserResult |
operation variables type | GetUserVariables | GetUserVariables |
Name of the operation document object (GetUserDocument
) still differ from nitrogql with the above setting. Since GraphQL Code Generator cannot exactly match the nitrogql behavior, we will guide you to configure nitrogql to match the resulting behavior of GraphQL Code Generator.
Migrating to nitrogql (applies to both client-side and server-side code)
Now it's time to migrate to nitrogql!
๐คฏ If you are in a monorepo setting, adjust below instructions as explained in the monorepo guide.
Install nitrogql
First, install nitrogql and its dependencies.
npm install -D @nitrogql/cli
If you are using webpack, you also need to install appropriate webpack loader. Note that this also applies to Next.js projects.
npm install -D @nitrogql/graphql-loader
If you are using Rollup, you need to install appropriate Rollup plugin. Note that this also applies to Vite projects.
npm install -D @nitrogql/rollup-plugin
Create nitrogql config
nitrogql's configuration file is either graphql.config.yaml
or .graphqlrc.yaml
at the root of your project. .js
or .ts
files are supported too. You might have already one depending on your GraphQL Code Generator configuration. Also, you can use .json
or .js
files instead of .yaml
at your preference.
You can reuse schema
and documents
options from your GraphQL Code Generator configuration. Start by copying them to your nitrogql configuration file:
# graphql.config.yaml
schema: src/schema/*.graphql
documents: src/app/**/*.graphql
Note that any other nitrogql options are put under extensions.nitrogql
object.
Configure schema output
One option you need to set is generate.schemaOutput
. This option controls where the generated schema type definition is written to. Set it to the path to the file where you want to write the schema type definition to. This option corresponds to the typescript
plugin of GraphQL Code Generator.
In nitrogql, the schema type definition file will be depended by other generated file (both client-side and server-side).
Also, if you are importing enums from the generated schema file, you need to set generate.emitSchemaRuntime
to true
. This is the default setting of GraphQL Code Generator, but nitrogql does not emit runtime enum definitions by default.
Example:
# GraphQL Code Generator configuration
generates:
path/to/schema.ts:
plugins:
- typescript
config:
# ...
# corresponding nitrogql configuration (graphql.config.yaml)
schema: src/schema/*.graphql
documents: src/app/**/*.graphql
extensions:
nitrogql:
generate:
schemaOutput: path/to/schema.ts
emitSchemaRuntime: true
Configure scalar types
If you have a customized mapping from GraphQL scalar types to TypeScript types, you need to migrate it to nitrogql's scalarTypes
option.
Migration from GraphQL Code Generator's scalars
option is straightforward. For example, if you have the following GraphQL Code Generator configuration:
# GraphQL Code Generator configuration
scalars:
ID:
input: string
output: string | number
DateTime: Date
You can migrate to nitrogql's scalarTypes
option as follows:
# corresponding nitrogql configuration (graphql.config.yaml)
extensions:
nitrogql:
generate:
# ...
type:
scalarTypes:
ID:
send: string | number
receive: string
DateTime: Date
Note that nitrogql's scalarTypes
option takes send
and receive
properties instead of input
and output
properties. Read more about the difference in the Configuring Scalar Types page.
Migrating client-side to nitrogql
If you are using GraphQL Code Generator for client-side code, belows steps apply.
Configure operation output
Next, you need to configure generation of TypeScript code from GraphQL operations. This corresponds to the typescript-operations
plugin of GraphQL Code Generator.
Without additional configuration, nitrogql generates TypeScript code next to each GraphQL operations files. This is the same architecture as GraphQL Code Generator's near-operation-file
preset.
However, you need to adjust nitrogql's generate
option so that you can use the generated code from your application in the same way as you did with GraphQL Code Generator.
Below is the nitrogql configuration for keeping the same behavior as your current settings.
schema: src/schema/*.graphql
documents: src/app/**/*.graphql
extensions:
nitrogql:
generate:
schemaOutput: path/to/schema.ts
emitSchemaRuntime: true
# add below
export:
defaultExportForOperation: false
variablesType: true
operationResultType: true
name:
queryVariableSuffix: Document
mutationVariableSuffix: Document
subscriptionVariableSuffix: Document
Configure TypeScript
In order to use the generated code from your application, you might need to adjust TypeScript configuration to recognize the generated code.
In your tsconfig.json
, set the allowArbitraryExtensions
compiler option to true
so that TypeScript lets you import .graphql
files.
Note that this option is only available in TypeScript 5.0 or later. If you are using an older version of TypeScript, you can set nitrogql's generate.mode
option to with-loader-ts-4.0
.
Configure webpack loader or Rollup plugin
As the last step, you need to configure webpack loader or Rollup plugin so that they can load .graphql
files.
If you are using webpack, add the following to your webpack configuration:
// webpack.config.js
module.exports = {
module: {
rules: [
// ...
{
test: /\.graphql$/,
use: [
{
loader: "@nitrogql/graphql-loader",
options: {
// path to your nitrogql configuration file
configFile: "./graphql.config.yaml",
},
},
],
},
],
},
};
If you are using Rollup, add the following to your Rollup configuration:
// rollup.config.js
import graphql from "@nitrogql/rollup-plugin";
export default {
// ...
plugins: [
// ...
graphql({
// path to your nitrogql configuration file
configFile: "./graphql.config.yaml",
include: ["**/*.graphql"],
}),
],
};
Migrating server-side to nitrogql
For server-side code, the role of GraphQL Code Generator is to generate type definitions for resolvers. nitrogql also supports generating such type definitions.
Configure resolver output
First of all, you need to configure generation of resolver type definitions file. This is done by setting the generate.resolverOutput
option.
Example:
# GraphQL Code Generator configuration
generates:
src/generated/resolvers.ts:
plugins:
- typescript-resolvers
config:
# ...
# corresponding nitrogql configuration (graphql.config.yaml)
schema: src/schema/*.graphql
documents: src/app/**/*.graphql
extensions:
nitrogql:
generate:
# ...
resolverOutput: src/generated/resolvers.ts
Apply the model
plugin
nitrogql has mechanism for generating significantly more type-safe definitions for resolvers. In return for this, use of the model
plugin is almost a must.
First, add the model
plugin to your nitrogql configuration:
extensions:
nitrogql:
plugins:
- "nitrogql:model-plugin"
# ...
Then, apply the @model
directive to your GraphQL schema.
If you are using GraphQL Code Generator's mappers
option, migration to nitrogql's model
plugin is straightforward.
# GraphQL Code Generator configuration
generates:
src/generated/resolvers.ts:
config:
# ...
mappers:
User: "~/models/User#User"
# nitrogql equivalent
type User @model(type: "import('~/models/User').User") {
# ...
}
Otherwise, you should annotate each object type field with @model
directive. The rule is that if you implement a resolver for a field, you do not need the @model
directive. Any field that does not have a resolver implementation (i.e. a field that is resolved by the default resolver) needs the @model
directive. Example:
type User {
id: ID! @model
name: String! @model
email: String! @model
posts: [Post!]!
}
Usage of generated resolver types
nitrogql's approach to generating resolver types is a little different from GraphQL Code Generator's.
GraphQL Code Generator outputs one type per GraphQL type. For example, if you have type Query
and type User
in your GraphQL schema, you get QueryResolvers
and UserResolvers
type generated by the typescript-resolvers
plugin.
nitrogql employs a different approach. It generates one type named Resolvers
that contains all information about resolvers. GraphQL Code Generator's UserResolvers
corresponds to nitrogql's Resolvers<Context>["User"]
.
// GraphQL Code Generator
import type { Resolvers, UserResolvers } from "~/generated/resolvers";
const userResolvers: UserResolvers = {
// ...
};
const resolvers: Resolvers = {
User: userResolvers,
// ...
};
// nitrogql
import type { Resolvers } from "~/generated/resolvers";
const userResolvers: Resolvers<Context>["User"] = {
// ...
};
const resolvers: Resolvers<Context> = {
User: userResolvers,
// ...
};
The goal of your resolver implementation should be the same as before migration. You should make a resolvers
object that contains all resolver implementations and pass it to your GraphQL server. If resolvers
has type Resolvers<Context>
, it should be safe in a sense that all resolver implementations have correct type and all required fields are implemented.
Note that there is another difference between GraphQL Code Generator and nitrogql in the handling of Context
. A context is additional data that is passed to all resolver implementations. In GraphQL Code Generator, you can specify the type of context in the typescript-resolvers
plugin's contextType
option so the exported Resolvers
type includes the context type. However, nitrogql does not have such option. Instead, nitrogql's Resolvers
type is a generic type that takes the context type as a type argument.
Therefore, you need to change the type of resolvers
to Resolvers<Context>
to match the type of Resolvers
generated by GraphQL Code Generator. If it is a problem for you, you can make an intermediate module that exports Resolvers<Context>
and import it from your resolver implementation module.
Using Server GraphQL File
This is not a mandatory step, but you can also take advantage of Server GraphQL File to make your GraphQL server implementation easier. If you are using file system operations to load your GraphQL schema, this file is a great alternative.
Using nitrogql CLI
After you migrate to nitrogql, you need to also migrate build scripts to use nitrogql CLI.
Basically, you need to replace graphql-codegen
command with nitrogql generate
.
Watch mode
nitrogql CLI does not have a watch mode for now. If you need a watch mode, you can use nodemon or chokidar-cli to watch GraphQL files and run nitrogql generate
automatically.
For example, if you are using chokidar-cli, a command for watching GraphQL files and running nitrogql generate
is as follows:
chokidar '**/*.graphql' --initial --command 'npx nitrogql generate'
๐งบ Read Next: Configuration, CLI Usage