{"id":11840,"library":"react-relay","title":"React Relay","description":"React Relay is a JavaScript framework developed by Meta for building highly performant and data-driven React applications using GraphQL. It provides a robust client-side data store, automatic query batching, optimistic updates, and a compile-time artifact generation process that ensures type safety and optimized network requests. Currently at version 20.1.1, Relay maintains an active development pace with frequent patch and minor releases, alongside major releases introducing significant features and breaking changes on a regular cadence. Key differentiators include its tight integration with GraphQL at a compiler level, enabling advanced optimizations like persisted queries and fragment colocation, and its comprehensive approach to client-side data management, including client-side state through Relay Resolvers. Its compiler tooling is a core component, transforming GraphQL declarations into optimized, type-safe code.","status":"active","version":"20.1.1","language":"javascript","source_language":"en","source_url":"https://github.com/facebook/relay","tags":["javascript","graphql","relay","react"],"install":[{"cmd":"npm install react-relay","lang":"bash","label":"npm"},{"cmd":"yarn add react-relay","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-relay","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for React application integration.","package":"react","optional":false}],"imports":[{"note":"Provides the Relay environment to the React component tree. Primarily used with ESM imports.","wrong":"const { RelayEnvironmentProvider } = require('react-relay')","symbol":"RelayEnvironmentProvider","correct":"import { RelayEnvironmentProvider } from 'react-relay'"},{"note":"This hook is for fetching a query's data on initial render (or component mount). Do not confuse with 'useQuery' from other GraphQL clients.","wrong":"import { useQuery } from 'react-relay'","symbol":"useLazyLoadQuery","correct":"import { useLazyLoadQuery } from 'react-relay'"},{"note":"Used to read data from a fragment. Requires a `graphql` tag with the fragment definition.","symbol":"useFragment","correct":"import { useFragment } from 'react-relay'"},{"note":"This template tag is essential for defining GraphQL queries, mutations, subscriptions, and fragments for the Relay compiler.","symbol":"graphql","correct":"import { graphql } from 'react-relay'"}],"quickstart":{"code":"import React from 'react';\nimport { \n  RelayEnvironmentProvider, \n  loadQuery, \n  useLazyLoadQuery, \n  graphql \n} from 'react-relay';\nimport { \n  Environment, \n  Network, \n  RecordSource, \n  Store \n} from 'relay-runtime';\n\n// 1. Define a Network Layer\nconst fetchGraphQL = async (text, variables) => {\n  const response = await fetch('https://swapi-graphql.netlify.app/.netlify/functions/index', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ query: text, variables }),\n  });\n  return await response.json();\n};\n\nconst network = Network.create(fetchGraphQL);\n\n// 2. Create a Relay Store\nconst store = new Store(new RecordSource());\n\n// 3. Create a Relay Environment\nconst environment = new Environment({\n  network,\n  store,\n});\n\n// 4. Define a Query\nconst AppQuery = graphql`\n  query AppQuery {\n    allFilms {\n      films {\n        title\n        releaseDate\n      }\n    }\n  }\n`;\n\n// 5. Pre-load the query for suspense (optional, but good practice)\nconst preloadedQuery = loadQuery(environment, AppQuery, {});\n\nfunction FilmList() {\n  const data = useLazyLoadQuery(AppQuery, {}, { fetchPolicy: 'store-or-network' });\n\n  return (\n    <div>\n      <h1>Star Wars Films</h1>\n      <ul>\n        {data.allFilms?.films?.map((film, index) => (\n          <li key={index}>{film?.title} (Released: {film?.releaseDate})</li>\n        ))}\n      </ul>\n    </div>\n  );\n}\n\nexport default function AppRoot() {\n  return (\n    <RelayEnvironmentProvider environment={environment}>\n      <React.Suspense fallback={<div>Loading...</div>}>\n        <FilmList />\n      </React.Suspense>\n    </RelayEnvironmentProvider>\n  );\n}","lang":"typescript","description":"This quickstart demonstrates setting up a basic Relay Environment, defining a GraphQL query, and using `useLazyLoadQuery` within a React component to fetch and display data, including Suspense for loading states. It connects to a public Star Wars API."},"warnings":[{"fix":"Add `@alias` directive to conditional fragments: `...MyFragment @alias(as: \"aliasedFragment\") on MyType` or configure your Relay compiler to opt-out of this validation for specific fragments.","message":"Since Relay v19.0.0, the `@alias` directive is now required on all fragments that are only conditionally fetched due to `@skip`/`@include` or fragment type conditions. This improves type safety and prevents runtime errors. You may opt out of this validation on a per-fragment basis if necessary.","severity":"breaking","affected_versions":">=19.0.0"},{"fix":"Review and update your GraphQL schema to ensure it is fully spec-compliant. The compiler output will provide specific error messages. You can temporarily opt out of some validations via Relay compiler configuration, but it's recommended to fix the schema.","message":"Relay v17.0.0 introduced stricter, spec-compliant schema validation, including client schema extensions and Relay Resolvers. This may cause existing valid GraphQL schemas (from older versions) to fail compilation.","severity":"breaking","affected_versions":">=17.0.0"},{"fix":"Update your `relay.config.js` (or equivalent) to change `customScalars: { ... }` to `customScalarTypes: { ... }`.","message":"In Relay v16.2.0, the compiler configuration option `customScalars` was renamed to `customScalarTypes` for single-project configuration files. If you are using custom scalars, this change requires an update to your `relay.config.js`.","severity":"breaking","affected_versions":">=16.2.0 <17.0.0"},{"fix":"Thoroughly review the official Relay Resolvers documentation. Ensure your client schema extensions accurately define resolver types and fields, and that the resolver functions correctly transform or derive data.","message":"Relay Resolvers, which enable structured and type-safe client-side state management, became stable in v18.1.0. While powerful, incorrect usage or misconfiguration can lead to unexpected client-side data behavior or type mismatches if not properly defined in your client schema extensions.","severity":"gotcha","affected_versions":">=18.1.0"},{"fix":"Upgrade `eslint-plugin-relay` to v2.0.0 or higher. Review the `eslint-plugin-relay` changelog for any removed or changed rules that may affect your codebase and update your ESLint configuration accordingly.","message":"The `eslint-plugin-relay` package (Relay's ESLint plugin) was updated to v2.0.0 alongside Relay v20.0.0. This release includes compatibility updates and removes deprecated rules. If you use the ESLint plugin, an upgrade may be necessary, and some linting rules might change or require re-configuration.","severity":"gotcha","affected_versions":">=20.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure that `RelayEnvironmentProvider` is rendered at the root of your application or above any components that utilize Relay hooks or components. Provide it with a valid `environment` prop: `<RelayEnvironmentProvider environment={relayEnvironment}>`.","cause":"The RelayEnvironmentProvider component, which supplies the Relay `Environment` to all hooks and components, is not rendered above the components trying to use Relay.","error":"Invariant Violation: Relay: Expected `RelayEnvironmentProvider` to be rendered higher in the tree."},{"fix":"Ensure your project is configured for ESM imports where `react-relay` is used, especially in modern React applications. Use `import { ... } from 'react-relay'` syntax. If using an older bundler or Node.js, ensure correct transpilation and module resolution is in place, or consider upgrading your tooling.","cause":"This typically indicates a CommonJS `require()` call trying to access an internal ESM-only module path, or a mismatch in module resolution in older Node.js/bundler environments with modern Relay versions.","error":"Error: Cannot find module 'react-relay/lib/relay-runtime/RelayRuntime' or similar module not found errors."},{"fix":"Ensure that the fragment reference you are passing to `useFragment` is always a valid object. Add null/undefined checks before rendering components that rely on `useFragment`, or use optional chaining if the fragment reference might legitimately be absent.","cause":"This error often occurs when a fragment reference passed to `useFragment` (or similar) is `null` or `undefined`, usually because of conditional rendering or data being unexpectedly missing.","error":"Invariant Violation: Relay: Expected all GraphQL fragments to be spread, got null or undefined."},{"fix":"Verify that the GraphQL query used to fetch the data explicitly includes all the fields required by the fragments that are being spread and consumed by child components. Ensure your `graphql` tags accurately reflect your data requirements.","cause":"A component or hook (e.g., `useFragment`) tried to access a field within a fragment that was not included in the corresponding GraphQL query that fetched the data.","error":"Relay: Missing fragment data for field `myField` on object `MyType`."}],"ecosystem":"npm"}