From 2db6c44b6ee23f1262d0bb5cade519bec59e25a4 Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Thu, 5 Feb 2026 15:32:07 +0200 Subject: [PATCH 1/2] add dev mode docs --- cspell.yml | 8 +- website/pages/docs/_meta.ts | 1 + website/pages/docs/development-mode.mdx | 396 +++++++++++++++++++++ website/pages/docs/getting-started.mdx | 13 +- website/pages/docs/going-to-production.mdx | 146 +------- website/pages/upgrade-guides/v16-v17.mdx | 36 +- 6 files changed, 464 insertions(+), 136 deletions(-) create mode 100644 website/pages/docs/development-mode.mdx diff --git a/cspell.yml b/cspell.yml index 49356561a7..a7e255dc1e 100644 --- a/cspell.yml +++ b/cspell.yml @@ -16,11 +16,13 @@ overrides: dictionaries: - fullstack words: - - clsx - - infima - - noopener + - callout - Vite - craco + - rollup + - Rsbuild + - Rspack + - Turbopack - esbuild - swcrc - noreferrer diff --git a/website/pages/docs/_meta.ts b/website/pages/docs/_meta.ts index 87858e5b73..79f17fa754 100644 --- a/website/pages/docs/_meta.ts +++ b/website/pages/docs/_meta.ts @@ -51,6 +51,7 @@ const meta = { type: 'separator', title: 'Production & Scaling', }, + 'development-mode': '', 'going-to-production': '', 'scaling-graphql': '', }; diff --git a/website/pages/docs/development-mode.mdx b/website/pages/docs/development-mode.mdx new file mode 100644 index 0000000000..6b2e43a08a --- /dev/null +++ b/website/pages/docs/development-mode.mdx @@ -0,0 +1,396 @@ +--- +title: Development Mode +--- + +import { Callout } from 'nextra/components'; + +# Development Mode + + + In v16 and earlier, development mode is enabled by default. Starting in v17, it + is disabled by default. + + + + In v16 and earlier, `NODE_ENV=production` disables development checks. Starting + in v17, development mode is controlled by exports conditions and `NODE_ENV` is + ignored. + + +In development mode, GraphQL.js can provide an additional runtime check appropriate +for development-time errors: the erroneous inclusion of multiple GraphQL.js modules. + +In v16 and earlier, development mode is enabled by default and controlled via +`NODE_ENV`. In v17, development mode is disabled by default to best ensure that +production builds do not incur the performance and bundle size penalties associated +with the additional checks. + +In v17, development mode is enabled only when the `development` exports condition +is active (some tool chains enable this automatically in development builds) or when +you call `enableDevMode()` in user code. The `NODE_ENV` environment variable has no +effect on development mode in v17. + +## Multiple GraphQL.js Modules + +Only a single GraphQL.js module can be used within a project. Different GraphQL.js +versions cannot be used at the same time since different versions may have different +capabilities and behavior. The data from one version used in the function from +another could produce confusing and spurious results. + +Duplicate modules of GraphQL.js of the same version may also fail at runtime, +sometimes in unexpected ways. This happens because GraphQL.js relies on +module-scoped objects for key features. For example, GraphQL.js uses `instanceof` +checks (v16) or unique symbols (v17) internally to distinguish between different +schema elements, which underpin the exported predicates such as `isScalarType()`, +`isObjectType()`, etc. Similarly, the exported constant `BREAK` allows library +users to control visitor behavior, but will fail when passed to a duplicate module. + +To ensure that only a single GraphQL.js module is used, all libraries depending on +GraphQL.js should use the appropriate peer dependency mechanism, as provided by +their package manager, bundler, build tool, or runtime. + +In development mode, GraphQL.js provides validation checks that should catch most +cases of multiple GraphQL.js modules being used within the same project. + +This additional validation is unnecessary in production, where the GraphQL.js +library is expected to have been set up correctly as a single module. In v16 and +earlier, this check is included by default and must be disabled by setting +`NODE_ENV=production`. In v17, it is only included when the `development` exports +condition is explicitly enabled or when `enableDevMode()` is called. + +## Enabling Development Mode + +### v16 and earlier + +Through v16, development mode is enabled by default and must be disabled in production +by setting `NODE_ENV=production`. + +```bash +NODE_ENV=development node server.js +NODE_ENV=production node server.js +``` + +Bundlers typically replace `process.env.NODE_ENV` at build time. See +`process.env.NODE_ENV` at build time, allowing development-only code paths to be +removed for production builds. + +The following examples show how to configure common bundlers to set +`process.env.NODE_ENV` and remove development-only code: + +#### Vite + +```js +// vite.config.js +import { defineConfig } from 'vite'; + +export default defineConfig({ + define: { + 'process.env.NODE_ENV': '"production"', + }, +}); +``` + +#### Next.js + +When you build your application with `next build` and run it using `next start`, +Next.js sets `process.env.NODE_ENV` to `'production'` automatically. No +additional configuration is required. + +```bash +next build +next start +``` + +If you run a custom server, make sure `NODE_ENV` is set manually. + +#### Create React App (CRA) + +To customize Webpack behavior in CRA, you can use a tool like +[`craco`](https://craco.js.org/). This example uses CommonJS syntax instead of +ESM syntax, which is required by `craco.config.js`: + +```js +// craco.config.js +const webpack = require('webpack'); + +module.exports = { + webpack: { + plugins: [ + new webpack.DefinePlugin({ + 'globalThis.process': JSON.stringify(true), + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + ], + }, +}; +``` + +#### esbuild + +```json +{ + "define": { + "globalThis.process": true, + "process.env.NODE_ENV": "production" + } +} +``` + +#### Webpack + +```js +// webpack.config.js +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export default { + mode: 'production', // Automatically sets NODE_ENV + context: __dirname, +}; +``` + +#### Rollup + +```js +// rollup.config.js +import replace from '@rollup/plugin-replace'; + +export default { + plugins: [ + replace({ + preventAssignment: true, + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + ], +}; +``` + +#### SWC + +```json filename=".swcrc" +{ + "jsc": { + "transform": { + "optimizer": { + "globals": { + "vars": { + "globalThis.process": true, + "process.env.NODE_ENV": "production" + } + } + } + } + } +} +``` + +### v17 + +Development mode can be enabled either by calling `enableDevMode()` or by using the +`development` exports condition. If your tooling already enables the `development` +condition in dev builds, dev mode is automatic. Otherwise, set it explicitly using +the options below. + +#### A Catch-All Option: Explicit Enabling of Development Mode + +Development mode may be enabled explicitly by calling `enableDevMode()`: + +```js +// entrypoint.js +import { enableDevMode } from 'graphql'; +enableDevMode(); +``` + +A bootstrapping file can be used to enable development mode conditionally: + +```js +// bootstrap.js +import process from 'node:process'; +import { enableDevMode } from 'graphql'; +if (process.env.NODE_ENV === 'development') { + enableDevMode(); +} +import './path/to/my/entry.js'; +``` + +The above is compatible with Node.js; the exact environment variable and method +of accessing it depends on the individual platform. + +#### Conditional Exports and Implicit Enabling of Development Mode + +Depending on your platform, you may be able to use the `development` condition to +enable development mode without the need for an explicit import. + +Conditional exports with custom conditions are supported by: Node.js, Deno, Bun, +Webpack 5, Rspack, Rollup (via the `node-resolve` plugin), esbuild, Vite, and +Rsbuild. create-react-app and Next.js support conditional exports when using +Webpack 5 as their bundler. + +Conditional exports with custom conditions are not supported by Webpack 4, Rollup +(without the `node-resolve` plugin), older versions of Deno or transpilers such as +swc. create-react-app and Next.js do not support conditional exports with custom +conditions when using Webpack 4 as their bundler, nor does Next.js yet support +conditional exports with custom conditions when using Turbopack (see +https://github.com/vercel/next.js/discussions/78912). + +Testing frameworks such as Mocha, Jest, and Vitest support conditional exports with +custom conditions, but require configuration as shown below. + +We encourage enabling development mode in a development environment. This +facilitates the additional check to ensure that only a single GraphQL.js module is +used. Additional development-time checks may also be added in the future. + +##### Node.js + +In Node.js, the development condition can be enabled by passing the +`--conditions=development` flag to the Node.js runtime. + +Alternatively, this can be included within the `NODE_OPTIONS` environment variable: + +```bash +export NODE_OPTIONS=--conditions=development +``` + +##### Deno + +In Deno version 2.4.0 and later, you can enable the development condition by +passing the `--conditions=development` flag to the runtime: + +```bash +deno run --conditions=development main.js +``` + +Alternatively, the `DENO_CONDITIONS` environment variable may be used: + +```bash +export DENO_CONDITIONS=development +``` + +##### Bun + +In Bun version 1.0.30 and later, you can enable the development condition by +passing the `--conditions=development` flag to the runtime: + +```bash +bun --conditions=development main.js +``` + +##### Webpack + +Webpack 5 supports the `development` condition natively and requires no additional +configuration. + +##### Rollup + +Rollup supports the `development` condition only when using the +`@rollup/plugin-node-resolve` plugin. + +```ts +// rollup.config.js +import resolve from '@rollup/plugin-node-resolve'; + +export default { + plugins: [ + resolve({ + exportConditions: ['development'], + }), + ], +}; +``` + +##### esbuild + +When using esbuild, you can enable the `development` condition by setting the +`--conditions=development` flag in your build command: + +```bash +esbuild --conditions=development entrypoint.js +``` + +Note that setting any custom conditions will drop the default `module` condition +(used to avoid the dual package hazard), so you may need to use: + +```bash +esbuild --conditions=development,module entrypoint.js +``` + +See further discussion within the [esbuild documentation](https://esbuild.github.io/api/#conditions) for +more details. + +##### Vite + +Vite supports the `development` condition natively and requires no additional +configuration. + +##### Next.js + +When using Webpack 5 as its bundler, Next.js supports the `development` condition +natively and requires no additional configuration. When using Webpack 4 or +Turbopack, development mode must be enabled explicitly. + +##### create-react-app + +When using Webpack 5 as its bundler, create-react-app supports the `development` +condition natively and requires no additional configuration. When using Webpack 4, +development mode must be enabled explicitly. + +##### Mocha + +Mocha supports the `development` condition by passing the appropriate configuration +to `node`: + +```bash +mocha --node-option conditions=development entrypoint.js +``` + +Options can also be passed to `node` via the `NODE_OPTIONS` environment variable: + +```bash +export NODE_OPTIONS=--conditions=development +``` + +##### Jest + +Jest supports the `development` condition by passing the appropriate configuration: + +```ts +// jest.config.ts +export const jestConfig = { + testEnvironmentOptions: { + customExportConditions: ['development'], + }, +}; +``` + +You may need to also include the `node` condition within the provided list: + +```ts +// jest.config.ts +export const jestConfig = { + testEnvironmentOptions: { + customExportConditions: ['development', 'node'], + }, +}; +``` + +##### Vitest + +Vitest supports the `development` condition by passing the appropriate +configuration: + +```ts +// vitest.config.ts +import { defineConfig } from 'vitest/config'; + +export const vitestConfig = defineConfig({ + resolve: { + conditions: ['development'], + }, + test: { + include: ['**/*.test.js'], + }, +}); +``` diff --git a/website/pages/docs/getting-started.mdx b/website/pages/docs/getting-started.mdx index 7a0286c890..0a12557526 100644 --- a/website/pages/docs/getting-started.mdx +++ b/website/pages/docs/getting-started.mdx @@ -20,13 +20,24 @@ and arrow functions, so if you aren't familiar with them you might want to read > Alternatively you can start from [this StackBlitz](https://stackblitz.com/edit/stackblitz-starters-znvgwr) - if you choose > this route you can skip to [Basic Types](./basic-types.mdx). -To create a new project and install GraphQL.js in your current directory: +GraphQL.js v16 is the current stable release. v17 is available as an alpha for +early testing and feedback. The alpha may change and should not be used in +production. + +To create a new project and install the latest stable release (v16) in your +current directory: ```sh npm2yarn npm init npm install graphql --save ``` +To try the v17 alpha instead: + +```sh npm2yarn +npm install graphql@alpha --save +``` + ## Writing Code To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a "resolver" for each API endpoint. For an API that just returns "Hello world!", we can put this code in a file named `server.js`: diff --git a/website/pages/docs/going-to-production.mdx b/website/pages/docs/going-to-production.mdx index da69a36942..2af1e0b7ab 100644 --- a/website/pages/docs/going-to-production.mdx +++ b/website/pages/docs/going-to-production.mdx @@ -2,143 +2,27 @@ title: Going to Production --- -# Going to Production - -GraphQL.JS contains a few development checks which in production will cause slower performance and -an increase in bundle-size. Every bundler goes about these changes different, in here we'll list -out the most popular ones. +import { Callout } from 'nextra/components'; -GraphQL.js includes development-time checks that are useful during local testing but should -be disabled in production to reduce overhead. Additional concerns include caching, error handling, -schema management, and operational monitoring. +# Going to Production This guide covers key practices to prepare a server built with GraphQL.js for production use. +Concerns include concerns include build optimization, caching, error handling, schema +management, and operational monitoring. ## Optimize your build for production -In development, GraphQL.js includes validation checks to catch common mistakes like invalid schemas -or resolver returns. These checks are not needed in production and can increase runtime overhead. - -You can disable them by setting `process.env.NODE_ENV` to `'production'` during your build process. -GraphQL.js will automatically skip over development-only code paths. - -Bundlers are tools that compile and optimize JavaScript for deployment. Most can be configured to -replace environment variables such as `process.env.NODE_ENV` at build time, -allowing for unused code (such as development only code paths) to be elided by -minification tools. - -### Bundler configuration examples - -The following examples show how to configure common bundlers to set `process.env.NODE_ENV` -and remove development-only code: - -#### Vite - -```js -// vite.config.js -import { defineConfig } from 'vite'; - -export default defineConfig({ - define: { - 'process.env.NODE_ENV': '"production"', - }, -}); -``` - -#### Next.js - -When you build your application with `next build` and run it using `next start`, Next.js sets -`process.env.NODE_ENV` to `'production'` automatically. No additional configuration is required. - -```bash -next build -next start -``` - -If you run a custom server, make sure `NODE_ENV` is set manually. - -#### Create React App (CRA) - -To customize Webpack behavior in CRA, you can use a tool like [`craco`](https://craco.js.org/). -This example uses CommonJS syntax instead of ESM syntax, which is required by `craco.config.js`: - -```js -// craco.config.js -const webpack = require('webpack'); - -module.exports = { - webpack: { - plugins: [ - new webpack.DefinePlugin({ - 'globalThis.process': JSON.stringify(true), - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - ], - }, -}; -``` - -#### esbuild - -```json -{ - "define": { - "globalThis.process": true, - "process.env.NODE_ENV": "production" - } -} -``` - -#### Webpack - -```js -// webpack.config.js -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - -export default { - mode: 'production', // Automatically sets NODE_ENV - context: __dirname, -}; -``` - -#### Rollup - -```js -// rollup.config.js -import replace from '@rollup/plugin-replace'; - -export default { - plugins: [ - replace({ - preventAssignment: true, - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - ], -}; -``` - -#### SWC - -```json filename=".swcrc" -{ - "jsc": { - "transform": { - "optimizer": { - "globals": { - "vars": { - "globalThis.process": true, - "process.env.NODE_ENV": "production" - } - } - } - } - } -} -``` +GraphQL.js includes development-time checks that are useful during local testing. For v16 and +earlier, these checks are enabled by default and should be disabled in production to reduce +overhead. See [Development Mode](./development-mode) for further details about these checks +and how to disable them. Starting in v17, development mode is disabled by default, and must +be explicitly enabled for development environments. + + + In v16 and earlier, development mode is enabled by default and must be explicitly disabled + in production. Starting in v17, development mode is disabled by default and may require + explicit enabling. See [Development Mode](./development-mode) for details and instructions. + ## Secure your schema diff --git a/website/pages/upgrade-guides/v16-v17.mdx b/website/pages/upgrade-guides/v16-v17.mdx index 00b8a27343..f853504436 100644 --- a/website/pages/upgrade-guides/v16-v17.mdx +++ b/website/pages/upgrade-guides/v16-v17.mdx @@ -12,6 +12,40 @@ import { Callout } from 'nextra/components' # Breaking changes +## Required Node.js versions + +The v17 release drops support for end-of-life versions of Node.JS, retaining support for versions 20, 22, and 24 or above. + +## ESM and conditional exports + +Earlier versions of GraphQL.js shipped dual builds for CommonJS and ESM, with ESM ".mjs" files sitting alongside CommonJS ".js" files. +The ESM build was accessible via tooling recognizing the `module` field in `package.json`, while the CommonJS build was accessible via +the `main` field. Unless configured carefully, this could sometimes lead to multiple copies of GraphQL.js being loaded in the same +process, i.e. the dual-package hazard. + +v17 enables access to the ESM build via the `exports` field in `package.json` in a scheme designed to avoid the dual-package hazard as +best as possible, relying on the ability of bun and newer versions of Node.js to consistently load ESM modules via `require` by +indicating support for specific conditions. __ESM will now be served by default__, unless the requesting environment tooling __both__ +(A) supports the `node` or `require` conditions __and__ (B) does NOT support `bun`, `module`, `module-sync`. In that scenario, the +CommonJS build will be served instead. + +Note: ESM is not served to deno even though it supports require(esm) because deno not yet support the `module-sync` condition, nor +does it seem to provide the `deno` condition when calling `require`, see https://github.com/denoland/deno/issues/29970. + +Deno users can access a Typescript build for deno via git://github.com/graphql/graphql-js.git#deno as well as by specifically loading +the index.mjs file, i.e. `import { graphql } from 'graphql/index.mjs'`, although this does not protect against the dual-package hazard. + +## Development mode no longer enabled by default and no longer dependent on NODE_ENV value + +GraphQl.js development mode in v17 is disabled by default and can be enabled by the `development` condition on supporting platforms or +by explicitly enabling it within user code by calling `enableDevMode()`. Development mode may trigger permanent de-optimizations and +therefore cannot be disabled once enabled. The new `isDevModeEnabled()` function can be used to check whether development mode has +been enabled. + +GraphQL.js development mode no longer depends on the `NODE_ENV` environment variable; build tools other than Node.js no longer need +to replace this Node.js specific code. See [Development Mode](./development-mode) for further details regarding how to enable these +checks in v17. + ## Default values GraphQL schemas allow default values for input fields and arguments. Historically, GraphQL.js did not rigorously validate or coerce these @@ -178,7 +212,7 @@ Use the `validateInputValue` helper to retrieve the actual errors. - Added `hideSuggestions` option to `execute`/`validate`/`subscribe`/... to hide schema-suggestions in error messages - Added `abortSignal` option to `graphql()`, `execute()`, and `subscribe()` allows cancellation of these methods; - the `abortSignal` can also be passed to field resolvers to cancel asynchronous work that they initiate. + `info.abortSignal` can also be used in field resolvers to cancel asynchronous work that they initiate. - `extensions` support `symbol` keys, in addition to the normal string keys. - Added ability for resolver functions to return async iterables. - Added `perEventExecutor` execution option to allows specifying a custom executor for subscription source stream events, which can be useful for preparing a per event execution context argument. From 00b74d7c0acb4ba15e7a63105433bb55b7ba9e5c Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Fri, 6 Mar 2026 00:04:49 +0200 Subject: [PATCH 2/2] edit heading --- website/pages/docs/development-mode.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/pages/docs/development-mode.mdx b/website/pages/docs/development-mode.mdx index 6b2e43a08a..194b274ed1 100644 --- a/website/pages/docs/development-mode.mdx +++ b/website/pages/docs/development-mode.mdx @@ -58,7 +58,7 @@ earlier, this check is included by default and must be disabled by setting `NODE_ENV=production`. In v17, it is only included when the `development` exports condition is explicitly enabled or when `enableDevMode()` is called. -## Enabling Development Mode +## Configuring Development Mode ### v16 and earlier