🎬 That's a Wrap for GraphQLConf 2024! • Watch the Videos • Check out the recorded talks and workshops
DocumentationDevelopment Mode

Development Mode

In development mode, GraphQL.JS can provides additional runtime check appropriate for development-time errors, including primarily the erroneous inclusion of multiple GraphQL.JS modules.

Unlike earlier versions of GraphQL.JS, by default, development mode is disabled. This is to best ensure that production builds do not incur the performance and bundle size penalties associated with the additional checks.

Also, unlike earlier versions, development mode is not configured by use of environment variables, which are accessed in disparate ways in varying environments. In particular, the NODE_ENV environment variable now has no effect on triggering development mode. Rather, development mode is either enabled:

  1. explicitly, by importing graphql/dev prior to other Graphql.JS imports or
  2. implicitly, by setting the ‘development’ condition, which is possible only in environments that support package.json conditional exports and custom conditions.

Conditional exports are supported by: Node.js, Deno (canary), Bun, Webpack 5, Rollup (via the node-resolve plugin), esbuild, and Vite. create-react-app and Next.js support conditional exports when using Webpack 5 as their bundler.

Conditional exports are not supported by Deno (current), Webpack 4, Rollup (without the node-resolve plugin), or swc. create-react-app and Next.js do not support conditional exports when using Webpack 4 as their bundler, nor does Next.js yet support conditional exports when using Turbopack (see https://github.com/vercel/next.js/discussions/78912).

We encourage enabling development mode within the development environments, either explicitly or implicitly. Additional development-time checks may also be added in the future. For now, the primary check is to ensure that only a single GraphQL.JS module is used. First, we will discuss the implications of using multiple GraphQL.JS modules, and then we will share additional details for how to enable development mode in various environments.

Multiple Graphql.JS Modules

Only a single GraphQL.JS 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 is because GraphQL.JS relies on the identity of the module for key features. Most significantly, instanceof checks are used throughout GraphQL.JS to identify and distinguish between GraphQL schema elements, such as the particular GraphQL type. Also, special exported constants like BREAK allow library users to manipulate visitor behavior, also relying on the module identity.

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 environment.

In development, GraphQL.JS provides a validation check triggered by any use of instanceof that should catch most cases of multiple GraphQL.js modules being used in the same project.

This additional validation is unnecessary in production, where the GraphQL.js library is expected to be have been setup correctly as a single module. So as to avoid the performance and bundle size overhead this check entails, it is only included when the development exports condition is explicitly enabled or when the graphql/dev module is explicitly imported before any other GraphQL.JS import.

Enabling Development Mode

A Catch-All Option: Explicit Enabling of Development Mode

Development mode is activated by importing the graphql/dev module before any other GraphQL.js import. Introducing a new bootstrapping entrypoint simplifies this workflow:

// bootstrap.js
import 'graphql/dev';
import './path/to/my/original-entry-point.js';

The bootstrapping file can be used to enable development mode conditionally:

import process from 'node:process';
// bootstrap.js
if (process.env.NODE_ENV === 'development') {
  await import('graphql/dev');
}
import './path/to/my/entry.js';

The above boiler plate is compatible with Node.js; the exact environment variable and method of accessing it depends on the individual environment and desired variable.

Conditional Exports and Implicit Enabling of Development Mode

Depending on your environment, you may be able to use the ‘development’ condition to enable development mode without the need for an explicit import.

Node.js

In Node.js, the development condition can be enabled by passing the --conditions=development flag to the Node.js runtime. This can be done within package.json scripts:

{
  "scripts": {
    "start": "node --conditions=development index.js"
  }
}

Alternatively, this can be included within the NODE_OPTIONS environment variable:

export NODE_OPTIONS="--conditions=development"

Deno

In Deno, conditional exports are not yet released, but are available within the canary build (see https://github.com/denoland/deno/issues/23757) as follows:

deno run --unstable-node-conditions=development main.js

Bun

In Bun, you can enable the development condition by passing the --conditions=development flag when running your script:

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.

//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:

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:

esbuild --conditions=development,module entrypoint.js

See further discussion within the esbuild documentation 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 require 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 support the ‘development’ condition natively and requires no additional configuration. When using Webpack 4, development mode must be enabled explicitly.