urql GraphQL Client for React
urql is a lightweight and highly customizable GraphQL client primarily designed for React applications, though it offers integrations for other frameworks like Vue and Svelte via separate packages. It is currently at version 5.0.2 and maintains an active development cycle with frequent patch and minor releases across its extensive ecosystem of exchanges and framework integrations. Its core differentiator is a pluggable 'exchanges' architecture, which allows developers to swap out or add functionalities like caching, authentication, request batching, and subscriptions, making it incredibly adaptable to various application requirements. Unlike some other clients, urql's core remains minimal, pushing advanced features into these composable exchanges, providing fine-grained control and reducing bundle size when not all features are needed. It ships with full TypeScript support.
Common errors
-
Client is not provided. Please make sure to add a `Provider`.
cause The `urql` client instance was not provided to your React component tree via the `<Provider>` component, or the component trying to use a hook (like `useQuery`) is outside the `Provider`'s scope.fixWrap your root React component (or the relevant part of your application) with `<Provider value={client}>...</Provider>`, where `client` is your initialized `urql` client instance. -
TypeError: (0 , urql__WEBPACK_IMPORTED_MODULE_2__.useQuery) is not a function
cause This typically indicates that `useQuery` was imported incorrectly, often due to trying to use `require()` syntax in a CommonJS context when the library expects ESM, or a bundler misconfiguration.fixEnsure you are using ES module imports: `import { useQuery } from 'urql'`. Verify your `tsconfig.json` (if TypeScript) and bundler configuration (`webpack.config.js`, `vite.config.ts`) are set up for ESM. -
Error: Objects are not valid as a React child (found: object with keys {__typename, id, title}). If you meant to render a collection of children, use an array instead.cause You are attempting to render a raw GraphQL data object directly within JSX without mapping or transforming it into valid React elements (e.g., strings, numbers, or React components).fixWhen rendering data from `useQuery`, iterate over arrays and access specific scalar properties. For example, instead of `<div>{data.allFilms.films}</div>`, use `<ul>{data.allFilms.films.map(film => <li key={film.title}>{film.title}</li>)}</ul>`.
Warnings
- breaking The `@urql/exchange-graphcache` package, often used with `urql` for normalized caching, introduced a major breaking change in version 9.0.0. It no longer serializes data to IndexedDB. This change invalidates all existing cached data and significantly impacts applications relying on persisted offline state through `graphcache`. While improving performance, it requires re-evaluating persistence strategies.
- gotcha urql and its core packages are primarily developed for ESM (ECMAScript Modules). While CJS (CommonJS) compatibility exists for older Node.js versions, using `require()` syntax with newer `urql` versions or in an ESM-first project can lead to module resolution errors or unexpected behavior.
- gotcha Incorrect or mismatched versions of `@urql/core` peer dependency with the `urql` package can lead to runtime errors, unexpected behavior, or type conflicts, especially during major version updates.
- deprecated Directly importing `Client` and instantiating it with `new Client({...})` is technically possible but `createClient` is the recommended approach for initializing your urql client instance. This function handles default setups and is often more future-proof.
Install
-
npm install urql -
yarn add urql -
pnpm add urql
Imports
- Provider
const { Provider } = require('urql')import { Provider } from 'urql' - useQuery
import urql from 'urql'; urql.useQuery()
import { useQuery } from 'urql' - Client configuration
import { Client } from 'urql'; new Client({})import { createClient, cacheExchange, fetchExchange } from 'urql'
Quickstart
import React from 'react';
import { createRoot } from 'react-dom/client';
import { createClient, Provider, cacheExchange, fetchExchange, useQuery } from 'urql';
// 1. Create your urql client
const client = createClient({
url: 'https://swapi-graphql.netlify.app/.netlify/functions/index', // Example public GraphQL API
exchanges: [cacheExchange, fetchExchange], // Define the exchanges to use (e.g., caching, fetching)
});
// 2. Define a React component that uses the useQuery hook
const StarWarsFilms = () => {
const [result] = useQuery({
query: `
query AllFilms {
allFilms {
films {
title
director
releaseDate
}
}
}
`,
});
const { data, fetching, error } = result;
if (fetching) return <p>Loading films...</p>;
if (error) return <p>Oh no... {error.message}</p>;
return (
<div>
<h1>Star Wars Films</h1>
<ul>
{data.allFilms.films.map((film) => (
<li key={film.title}>
<strong>{film.title}</strong> by {film.director} (Released: {film.releaseDate})
</li>
))}
</ul>
</div>
);
};
// 3. Wrap your root component with the Provider
const App = () => (
<Provider value={client}>
<StarWarsFilms />
</Provider>
);
// 4. Render your application
const container = document.getElementById('root');
if (container) {
const root = createRoot(container);
root.render(<App />);
} else {
console.error("Root element not found");
}