@urql/core vs apollo-client vs graphql-request
GraphQL Client Libraries for Frontend Architecture
@urql/coreapollo-clientgraphql-requestSimilar Packages:

GraphQL Client Libraries for Frontend Architecture

@urql/core, apollo-client, and graphql-request are tools for interacting with GraphQL APIs, but they serve different architectural needs. @urql/core is a modular, framework-neutral core library that powers the urql ecosystem, offering customizable caching and logic through exchanges. apollo-client is the legacy package for the Apollo GraphQL client, now deprecated in favor of @apollo/client, known for its robust caching and state management features. graphql-request is a minimalistic HTTP client for GraphQL, focusing on simplicity without built-in caching or state management, making it ideal for scripts or server-side usage.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@urql/core08,971323 kB302 months agoMIT
apollo-client019,813-4046 years agoMIT
graphql-request06,118420 kB599 months agoMIT

GraphQL Client Libraries for Frontend Architecture

When building applications that rely on GraphQL, choosing the right client library shapes your data flow, caching strategy, and overall code maintenance. @urql/core, apollo-client, and graphql-request represent three distinct approaches to solving this problem. Let's break down how they handle common engineering challenges.

πŸ—„οΈ Caching and State Management

@urql/core uses a modular exchange system to handle caching.

  • You configure a cacheExchange to store results.
  • It supports normalized caching but keeps it optional and configurable.
// @urql/core: Configuring cache exchange
import { createClient, cacheExchange } from '@urql/core';

const client = createClient({
  url: '/graphql',
  exchanges: [cacheExchange, fetchExchange]
});

apollo-client (Legacy) includes a powerful normalized cache out of the box.

  • It automatically updates UI when cache data changes.
  • Note: This package is deprecated; modern projects should use @apollo/client.
// apollo-client: Legacy cache setup
import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';

const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache()
});

graphql-request does not include caching or state management.

  • It sends raw HTTP requests and returns promises.
  • You must pair it with external tools (like React Query) for caching.
// graphql-request: No built-in cache
import { request } from 'graphql-request';

const query = `{ user { id } }`;
const data = await request('/graphql', query);
// Manual caching required elsewhere

βš™οΈ Setup and Configuration Complexity

@urql/core balances flexibility with simplicity.

  • You define exchanges to handle logging, caching, and fetching.
  • Setup is straightforward but allows deep customization.
// @urql/core: Custom exchange setup
import { createClient, fetchExchange } from '@urql/core';

const client = createClient({
  url: '/graphql',
  exchanges: [fetchExchange]
});

apollo-client requires more initial configuration.

  • You need to set up links, cache, and often context providers.
  • More boilerplate is needed for advanced features.
// apollo-client: Legacy link setup
import { createHttpLink } from 'apollo-link-http';
import ApolloClient from 'apollo-client';

const link = createHttpLink({ uri: '/graphql' });
const client = new ApolloClient({ link });

graphql-request has the lowest setup barrier.

  • Instantiate a client or use the standalone request function.
  • No complex providers or context needed.
// graphql-request: Minimal setup
import { GraphQLClient } from 'graphql-request';

const client = new GraphQLClient('/graphql');
const data = await client.request(query);

πŸ›‘ Deprecation and Maintenance Status

@urql/core is actively maintained.

  • It serves as the core for framework-specific packages like @urql/react.
  • Safe for long-term use in production.
// @urql/core: Current standard usage
import { createClient } from '@urql/core';
// Actively developed by Formidable

apollo-client is officially deprecated.

  • It receives no new features or security updates.
  • Using it in new projects introduces technical debt.
// apollo-client: Deprecated warning
// npm install apollo-client // DO NOT USE
// Use @apollo/client instead

graphql-request is actively maintained.

  • It focuses on stability and minimalism.
  • Safe for scripts and simple clients.
// graphql-request: Current standard usage
import { request } from 'graphql-request';
// Actively maintained community project

πŸ”’ Type Safety and Code Generation

All three tools work well with GraphQL code generators like graphql-code-generator, but integration differs.

@urql/core supports typed clients via plugins.

  • You can generate typed hooks or client wrappers.
  • Type safety is strong when configured.
// @urql/core: Typed query
import { typedClient } from './generated';
const result = await typedClient.query(UserQuery);

apollo-client supports TypeScript natively.

  • Generics on hooks provide type safety.
  • Legacy package has older type definitions.
// apollo-client: Typed query (Legacy)
import { gql } from 'apollo-client';
const query = gql`{ user { id } }`;

graphql-request generates typed SDKs easily.

  • The codegen tool can output a ready-to-use SDK.
  • Very clean developer experience for types.
// graphql-request: Generated SDK
import { getSdk } from './generated';
const sdk = getSdk(client);
const { user } = await sdk.GetUser();

🀝 Similarities: Shared Ground

While the differences are clear, these libraries share some core capabilities.

1. 🌐 GraphQL Protocol Support

  • All three send valid GraphQL queries and mutations.
  • Support headers, variables, and context.
// All support variables
const variables = { id: 1 };
// urql: client.query(query, variables)
// apollo: client.query({ query, variables })
// request: request(url, query, variables)

2. πŸ”Œ Extensibility

  • All allow custom headers or middleware logic.
  • You can intercept requests before they send.
// All support headers
// urql: context in operation
// apollo: link middleware
// graphql-request: headers in constructor

3. πŸ“¦ Ecosystem Integration

  • All work with Node.js and browsers.
  • Compatible with major build tools (Vite, Webpack).
// All import via npm
import { ... } from 'package-name';

πŸ“Š Summary: Key Differences

Feature@urql/coreapollo-clientgraphql-request
Statusβœ… Active❌ Deprecatedβœ… Active
CachingπŸ—„οΈ Modular (Exchange)πŸ—„οΈ Built-in (InMemory)❌ None
Setupβš™οΈ Mediumβš™οΈ Highβš™οΈ Low
Framework🧩 Neutral (Core)βš›οΈ React Focused (Legacy)🌍 Universal
Bundle SizeπŸ“¦ SmallπŸ“¦ LargeπŸ“¦ Minimal

πŸ’‘ The Big Picture

@urql/core is like a customizable engine πŸŽοΈβ€”great for teams that want control over how data flows without being locked into a specific framework. It shines when you need to build custom bindings or want a lighter alternative to Apollo.

apollo-client is like a legacy enterprise system πŸ’β€”powerful but outdated. Do not use it for new work. If you need its feature set, migrate to @apollo/client.

graphql-request is like a lightweight utility knife πŸ”ͺβ€”perfect for simple tasks, server-side scripts, or when you want to handle caching yourself. It removes magic and gives you raw control.

Final Thought: For new frontend applications, avoid apollo-client entirely. Choose @urql/core if you want a balanced, modern client with caching. Choose graphql-request if you prefer minimalism and plan to manage state elsewhere.

How to Choose: @urql/core vs apollo-client vs graphql-request

  • @urql/core:

    Choose @urql/core if you need a flexible, framework-neutral GraphQL client with customizable caching and logic. It is ideal for teams that want to build custom bindings for specific frameworks or need fine-grained control over request handling without the heavy footprint of larger libraries.

  • apollo-client:

    Do NOT choose apollo-client for new projects as it is officially deprecated. Instead, evaluate @apollo/client if you need a feature-rich client with advanced caching, state management, and strong React integration. It suits large-scale applications requiring complex data synchronization.

  • graphql-request:

    Choose graphql-request if you need a lightweight, zero-dependency client for simple queries, server-side scripts, or when you plan to manage caching and state with other tools like React Query. It is perfect for scenarios where minimal setup and raw HTTP control are priorities.

README for @urql/core

@urql/core

The shared core for the highly customizable and versatile GraphQL client, urql

More documentation is available at formidable.com/open-source/urql.