urql logo

urql

高度可扩展且轻量级的 GraphQL 客户端

GraphQL客户端API轻量级Exchange架构

urql(universal React QL)是一个高度可定制、轻量级的 GraphQL 客户端,核心创新在于 Exchange 交换器架构——一种函数式管道中间件机制。支持 React/Preact/Vue/Solid/Svelte 多框架,核心包 gzip 约 10-12 KB,远小于 Apollo Client。GitHub 约 9,000 Stars,是 GraphQL 生态中最轻量的客户端之一。

urql

高度可扩展且轻量级的 GraphQL 客户端

技术简介说明

urql(全称 "universal React QL")是一个高度可定制、轻量级的 GraphQL 客户端,由 Formidable 团队创建,目前由 urql-graphql 团队持续维护。它的设计哲学是"渐进式复杂度"——你可以从一个极简的 GraphQL 客户端开始,仅在需要时才引入高级功能(如规范化缓存),而非被迫接受一个庞大而复杂的全能方案。这种设计理念使其成为 GraphQL 生态中最轻量、最灵活的客户端之一。

urql 的核心创新在于其 Exchange(交换器)架构——一种类似中间件的管道机制,所有 GraphQL 操作都经过一系列可组合的 Exchange 进行处理。这种设计让开发者可以精确控制请求的去重、缓存、重试、鉴权、日志等各个环节,甚至可以在不修改核心代码的情况下完全改变客户端的行为。相比 Apollo Client 的 Link 机制,urql 的 Exchange 提供了更强的函数式组合能力和更低的运行时开销。

urql 是一个真正的多框架客户端,通过单一核心包 @urql/coreReact、Preact、Vue、Solid 和 Svelte 提供官方绑定。这意味着团队可以在不同框架之间共享同一套 GraphQL 逻辑和缓存策略,而无需为每个框架引入不同的客户端库。截至 2026 年 7 月,urql 的 React 主包已更新至 5.0.3 版本,核心包 @urql/core 已更新至 6.0.3 版本,持续活跃发展。


基本信息

项目内容
官网https://urql.dev
文档https://nearform.com/open-source/urql/
GitHubhttps://github.com/urql-graphql/urql
LicenseMIT
最新版本(React 主包 urql5.0.3(2026 年 7 月)
最新版本(核心包 @urql/core6.0.3(2026 年 7 月)
GitHub Stars~9,000
主要语言TypeScript(约 90%)
维护者urql-graphql 团队(原 Formidable Labs)
框架支持React、Preact、Vue、Solid、Svelte
包管理npm / pnpm / yarn

快速上手

安装

根据你使用的框架选择对应的包:

# React
npm install urql @urql/core graphql
 
# Preact
npm install @urql/preact @urql/core graphql
 
# Vue
npm install @urql/vue @urql/core graphql
 
# Solid
npm install @urql/solid @urql/core graphql
 
# Svelte
npm install @urql/svelte @urql/core graphql
 
# 规范化缓存(可选,所有框架通用)
npm install @urql/exchange-graphcache

使用 pnpm:

pnpm add urql @urql/core graphql
pnpm add @urql/exchange-graphcache  # 可选

基础配置

React 示例

import { createClient, Provider } from 'urql'
 
const client = createClient({
  url: 'https://api.example.com/graphql',
  // 可选:配置 exchanges
  // exchanges: [dedupExchange, cacheExchange, fetchExchange]
})
 
function App() {
  return (
    <Provider value={client}>
      <YourApp />
    </Provider>
  )
}

Vue 示例

import { createClient, installUrql } from '@urql/vue'
 
const client = createClient({
  url: 'https://api.example.com/graphql',
})
 
const app = createApp(App)
app.use(installUrql, client)

最小示例

import { useQuery, gql } from 'urql'
 
const TodosQuery = gql`
  query Todos {
    todos {
      id
      title
    }
  }
`
 
function Todos() {
  const [result] = useQuery({ query: TodosQuery })
 
  if (result.fetching) return <p>加载中...</p>
  if (result.error) return <p>出错了:{result.error.message}</p>
 
  return (
    <ul>
      {result.data?.todos.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

核心概念与架构

Exchange 交换器机制

urql 的架构核心是 Exchange——一种函数式管道中间件。每个 Exchange 是一个高阶函数,接收一个 ExchangeInput 并返回一个函数,该函数接收一个操作流(Source&lt;Operation&gt;),返回一个结果流(Source&lt;OperationResult&gt;)。

Client → [DedupExchange] → [CacheExchange] → [FetchExchange] → GraphQL Server
         ↑                                                          |
         └────────────── 结果流(Observable/Source) ───────────────┘

默认的三个 Exchange:

Exchange职责
dedupExchange去重——防止相同操作被重复发送
cacheExchange文档缓存——基于请求结果的简单缓存
fetchExchange网络请求——实际发送 HTTP 请求到 GraphQL 端点

自定义 Exchange 示例:

import { Exchange, Operation, OperationResult } from '@urql/core'
import { pipe, tap, map } from 'wonka'
 
const loggerExchange: Exchange = ({ forward }) => {
  return (ops$) => {
    return pipe(
      ops$,
      tap((op) => console.log('[urql] 操作:', op.kind, op.key)),
      forward,
      tap((result) => console.log('[urql] 结果:', result.data))
    )
  }
}
 
const client = createClient({
  url: 'https://api.example.com/graphql',
  exchanges: [loggerExchange, dedupExchange, cacheExchange, fetchExchange],
})

Client 设计

urql 的 Client 是所有操作的入口点,它负责:

  1. 管理 Exchange 链——按顺序执行所有 Exchange
  2. 创建操作(Operations)——将查询、变更、订阅转化为统一的操作对象
  3. 调度结果——将结果推送给订阅者(React hooks、Vue composables 等)

Client 支持四种请求策略(requestPolicy):

策略行为
cache-first优先缓存(默认)
cache-only仅缓存,无缓存则报错
network-only仅网络,跳过缓存
cache-and-network先返回缓存,再请求网络更新

缓存策略

urql 提供两级缓存:

  1. 文档缓存(Document Cache)——内置于 cacheExchange,按查询文档和变量缓存完整响应。适合简单场景,开箱即用。
  2. 规范化缓存(Normalized Cache)——通过 @urql/exchange-graphcache 提供,将数据拆分为独立实体并按 ID 索引,支持跨查询自动更新。适合复杂数据关系场景。

核心特性

1. 渐进式复杂度

urql 的设计哲学是"按需引入复杂度"。最简单的配置只需要一个 URL 和一个 useQuery hook,没有任何样板代码。当需求增长时,可以逐步添加自定义 Exchange、规范化缓存等高级功能,而无需重构现有代码。

2. Exchange 函数式管道

Exchange 机制是 urql 最核心的差异化特性。它基于 Wonka(一个类似 RxJS 的轻量流库),提供强大的函数式组合能力。开发者可以用 pipemapfiltermergeMap 等组合子自由编排请求处理逻辑,实现日志、鉴权、重试、离线支持等功能。

3. 多框架统一核心

一个 @urql/core 核心包 + 框架专属绑定(urql@urql/vue@urql/svelte 等),确保跨框架一致性。团队成员可以在不同项目中使用不同的框架,但共享同一套 GraphQL 逻辑和缓存策略。

4. 轻量级体积

urql 的核心包体积远小于 Apollo Client。@urql/core 的 minified+gzip 体积约 10-12 KB,而 Apollo Client 约 35-40 KB。在 bundle size 敏感的场景(如移动端、SSR)中优势明显。

5. 规范化缓存(Graphcache)

@urql/exchange-graphcache 是 urql 的官方规范化缓存方案。它将 GraphQL 响应拆分为独立实体,按 __typename + id 索引,支持:

  • 自动跨查询更新
  • 乐观更新(Optimistic Updates)
  • 缓存失效策略配置
  • Schema 感知的缓存失效

6. 服务端渲染(SSR)支持

urql 原生支持 SSR,提供 @urql/next 包用于 Next.js 集成。支持 prefetchrehydrate 等 SSR 模式,确保服务端渲染的数据能无缝传递到客户端。

7. TypeScript 优先

urql 从底层使用 TypeScript 构建,提供完整的类型推导。查询结果类型可以通过 graphql-codegen 自动生成,与查询文档保持同步。

8. 订阅支持

原生支持 GraphQL Subscriptions,可通过 @urql/exchange-graphcache 配合使用,也可使用 @urql/exchange-subscriptions 管理订阅连接。

9. 开发者工具

提供 urql DevTools 浏览器扩展,支持:

  • 查看所有 GraphQL 操作和响应
  • 检查缓存状态
  • 调试 Exchange 管道
  • 查看操作时间线

10. 请求策略灵活性

四种内置请求策略(cache-firstcache-onlynetwork-onlycache-and-network)覆盖了绝大多数缓存场景,且可以按查询粒度配置。


生态图

┌─────────────────────────────────────────────────────────────┐
│                      urql 生态系统                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  核心层                                                      │
│  ├── @urql/core          — 框架无关的核心引擎                 │
│  │                                                             │
│  框架绑定层                                                    │
│  ├── urql                — React / Preact 绑定               │
│  ├── @urql/vue           — Vue 3 绑定                        │
│  ├── @urql/svelte        — Svelte 绑定                       │
│  ├── @urql/solid         — Solid.js 绑定                     │
│  ├── @urql/preact        — Preact 专用绑定                    │
│  │                                                             │
│  缓存层                                                       │
│  ├── @urql/exchange-graphcache — 规范化缓存(核心扩展)        │
│  │                                                             │
│  平台集成层                                                    │
│  ├── @urql/next          — Next.js 集成(SSR/RSC)            │
│  │                                                             │
│  Exchange 扩展                                                 │
│  ├── @urql/exchange-retry        — 自动重试                    │
│  ├── @urql/exchange-request-policy — 请求策略控制              │
│  ├── @urql/exchange-execute      — 本地 Schema 执行           │
│  ├── @urql/exchange-context      — 动态上下文注入              │
│  ├── @urql/exchange-persisted    — 持久化查询(APQ)           │
│  │                                                             │
│  开发工具                                                      │
│  ├── urql-devtools         — 浏览器开发者工具扩展              │
│  │                                                             │
│  代码生成                                                      │
│  ├── graphql-codegen       — 配合使用自动生成类型               │
│  │                                                             │
│  社区扩展(第三方)                                              │
│  ├── urql-exchange-auth    — 鉴权 Exchange                     │
│  ├── urql-multipart        — 文件上传支持                      │
│  ├── @nanostores/urql      — Nanostores 状态管理集成           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

适用场景

1. Bundle Size 敏感的应用

当应用体积是关键指标(如移动端 Web、PWA、嵌入式 Web 视图),urql 的轻量体积(核心约 10KB gzip)相比 Apollo Client(约 35KB gzip)有显著优势。

2. 需要深度定制请求流程的场景

Exchange 机制允许开发者在请求管道的任何环节注入自定义逻辑,适合需要复杂鉴权、动态重试、离线队列、请求转换等高级场景。

3. 多框架团队 / Monorepo

统一核心 + 多框架绑定的设计,使得 urql 成为多框架团队的理想选择。一个核心包服务 React、Vue、Svelte 等多个子应用,减少依赖碎片化。

4. 中小型 GraphQL 应用

对于不需要 Apollo Client 全部功能的中小型应用,urql 提供了"恰到好处"的功能集——足够强大,但不臃肿。

5. Next.js / SSR 项目

@urql/next 提供了开箱即用的 Next.js 集成,支持 App Router、Server Components、prefetch 等现代 SSR 模式。

6. 需要逐步引入复杂度的项目

从简单的文档缓存开始,按需引入规范化缓存、自定义 Exchange 等高级功能。适合那些不确定最终需求复杂度的探索性项目。

7. 教育和学习 GraphQL

urql 的 API 设计简洁直观,核心概念少,非常适合作为学习 GraphQL 客户端的入门工具。


开发与工程化

TypeScript 集成

urql 提供完整的 TypeScript 支持,推荐配合 graphql-codegen 使用:

# 安装代码生成工具
npm install -D @graphql-codegen/cli @graphql-codegen/typed-document-node
# codegen.yml
generates:
  src/generated/graphql.ts:
    plugins:
      - typed-document-node
    documents: 'src/**/*.graphql'
    schema: 'https://api.example.com/graphql'
// 使用生成的类型安全查询
import { GetTodosDocument } from './generated/graphql'
import { useQuery } from 'urql'
 
const [result] = useQuery({ query: GetTodosDocument })
// result.data 类型自动推导

测试策略

urql 提供了 createClient 的 mock 支持,便于单元测试:

import { createClient, gql } from '@urql/core'
import { pipe, subscribe } from 'wonka'
 
const mockClient = createClient({
  url: 'test',
  fetch: async () => ({
    status: 200,
    json: async () => ({
      data: { todos: [{ id: '1', title: '测试任务' }] },
    }),
  } as Response),
})
 
// 测试查询
const result = await pipe(
  mockClient.query(gql`query { todos { id title } }`),
  subscribe(() => {})
)

CI/CD 集成

urql 本身无特殊 CI 需求,标准 Node.js 项目配置即可。推荐在 CI 中加入 GraphQL schema 检查:

# .github/workflows/graphql-check.yml
- name: GraphQL Schema Check
  run: npx @graphql-inspector/cli validate src/**/*.graphql schema.graphql

Monorepo 配置

在 Turborepo/pnpm workspace 中,推荐将 @urql/core 和框架绑定提升到根 package.json,避免多版本冲突:

// package.json (root)
{
  "pnpm": {
    "overrides": {
      "@urql/core": "^6.0.0"
    }
  }
}

性能与安全

性能优化

优化点说明
请求去重dedupExchange 自动合并相同操作,避免重复请求
文档缓存内置文档级缓存,减少不必要的网络请求
流式处理基于 Wonka 的流式架构,避免不必要的重渲染
Tree-shaking完全支持 tree-shaking,未使用的功能不会进入打包产物
惰性求值Exchange 管道按需执行,不处理不需要的操作
批量请求可配合 @urql/exchange-batch 合并多个查询请求

安全实践

安全点说明
凭证传输支持 fetchOptions 配置 credentialsheaders
鉴权 Exchange通过自定义 Exchange 注入 token,避免在查询中暴露敏感信息
CSRF 防护通过 credentials: 'include' + CSRF header 实现
持久化查询@urql/exchange-persisted 支持 APQ(Automatic Persisted Queries),减少查询注入风险
输入验证建议在服务端做 GraphQL 输入验证,urql 负责传输层安全

鉴权 Exchange 示例

const authExchange: Exchange = ({ forward }) => {
  return (ops$) => {
    return pipe(
      ops$,
      map((op) => {
        const token = getAuthToken()
        return {
          ...op,
          context: {
            ...op.context,
            fetchOptions: {
              ...op.context.fetchOptions,
              headers: {
                ...op.context.fetchOptions?.headers,
                Authorization: token ? `Bearer ${token}` : '',
              },
            },
          },
        }
      }),
      forward
    )
  }
}

技术对比

urql vs Apollo Client vs Relay

维度urqlApollo ClientRelay
包体积(gzip)~12 KB(核心)~35-40 KB~25-30 KB(Runtime)
学习曲线
缓存方式文档缓存 + 可选规范化缓存内置规范化缓存内置规范化缓存(强制)
可扩展性Exchange 函数式管道Apollo Link 链Compiler 插件
框架支持React / Vue / Svelte / Solid / PreactReact / Vue / Angular / Vanilla仅 React
TypeScript原生支持,完整推导原生支持原生支持
SSR 支持原生 + @urql/next原生 + @apollo/extrasNext.js 集成
DevTools有(urql DevTools)有(Apollo DevTools,更成熟)无独立 DevTools
社区规模中等(~9K stars)最大(~60K stars)大(~28K stars)
维护者urql-graphql 团队Apollo 团队Meta(Facebook)
GraphQL 规范完整支持完整支持完整支持(含 @defer/@stream)
Schema 驱动可选可选强制(需要 compiler)
规范化缓存可选(graphcache)内置(核心特性)内置(Store)
乐观更新通过 graphcache内置 cache.modify内置
订阅原生支持原生支持原生支持
代码生成配合 graphql-codegen配合 graphql-codegen专属 Relay Compiler
适合场景轻量应用、多框架、定制需求中大型应用、快速开发超大型应用、数据密集

选型建议

  • 选 urql:当 bundle size 是硬约束、需要多框架统一、或需要深度定制请求管道时
  • 选 Apollo Client:当需要开箱即用的完整方案、丰富的社区生态、或团队对 GraphQL 经验有限时
  • 选 Relay:当应用规模极大、数据关系极复杂、且团队有能力投入学习成本时

最佳实践

1. 从文档缓存开始

不要一开始就引入 graphcache。urql 内置的文档缓存已经能覆盖大多数场景。只有当你发现跨查询数据同步成为问题时,才考虑升级到规范化缓存。

// 推荐:先使用默认配置
const client = createClient({
  url: '/api/graphql',
})
 
// 需要时再添加 graphcache
import { cacheExchange } from '@urql/exchange-graphcache'
 
const client = createClient({
  url: '/api/graphql',
  exchanges: [
    dedupExchange,
    cacheExchange({
      keys: {
        // 自定义缓存键
      },
      updates: {
        Mutation: {
          createTodo: (result, args, cache) => {
            cache.invalidate({ __typename: 'Todo', id: args.input.id })
          },
        },
      },
    }),
    fetchExchange,
  ],
})

2. 使用 TypedDocumentNode

始终使用类型安全的查询文档,避免手写泛型:

// 推荐:使用 TypedDocumentNode
import { TypedDocumentNode } from '@urql/core'
 
const TodosQuery: TypedDocumentNode<{ todos: Todo[] }, {}> = gql`
  query Todos {
    todos {
      id
      title
      completed
    }
  }
`
 
// 或者使用 graphql-codegen 自动生成

3. 合理拆分 Exchange

将不同职责的逻辑拆分为独立的 Exchange,而非写一个巨大的 Exchange:

// 推荐:职责分离
const client = createClient({
  url: '/api/graphql',
  exchanges: [
    dedupExchange,
    authExchange,        // 鉴权
    loggerExchange,      // 日志
    retryExchange,       // 重试
    cacheExchange,       // 缓存
    fetchExchange,       // 网络
  ],
})

4. 利用请求策略

根据场景选择合适的请求策略,而非总是使用默认值:

// 用户列表:cache-and-network(先展示缓存,再更新)
const [result] = useQuery({
  query: UsersQuery,
  requestPolicy: 'cache-and-network',
})
 
// 表单提交后的详情查询:network-only(确保最新数据)
const [result] = useQuery({
  query: UserDetailsQuery,
  variables: { id },
  requestPolicy: 'network-only',
})

5. SSR 时注意数据序列化

在 Next.js 中使用 urql 时,确保正确处理服务端到客户端的数据传递:

// app/layout.tsx
import { Provider, createClient, fetchExchange, cacheExchange } from 'urql'
import { registerExchange } from '@urql/next'
 
const client = createClient({
  url: 'https://api.example.com/graphql',
  exchanges: [cacheExchange, fetchExchange],
})
 
export default function RootLayout({ children }) {
  return (
    <Provider value={client}>
      {children}
    </Provider>
  )
}

6. 避免不必要的重渲染

使用 useMemo 缓存查询变量,避免每次渲染都创建新对象:

function TodoList({ status }: { status: string }) {
  const variables = useMemo(() => ({ status }), [status])
  const [result] = useQuery({
    query: TodosQuery,
    variables,
  })
  // ...
}

7. 错误边界处理

为 GraphQL 错误设置全局处理逻辑:

const errorExchange: Exchange = ({ forward }) => {
  return (ops$) => {
    return pipe(
      ops$,
      forward,
      tap(({ error, operation }) => {
        if (error) {
          // 全局错误处理:上报、Toast 等
          console.error(`[GraphQL Error] ${operation.kind}:`, error)
          errorReporter.capture(error)
        }
      })
    )
  }
}

技术局限与边界

已知局限

  1. 社区规模较小:相比 Apollo Client(~60K stars),urql 的社区规模较小(~9K stars),第三方生态、教程和问答资源相对有限。遇到复杂问题时,可能需要直接阅读源码。

  2. 规范化缓存功能较弱@urql/exchange-graphcache 功能完备性不如 Apollo Client 的内置缓存。例如,cache.modify 等高级缓存操作 API 不如 Apollo 丰富,跨查询的复杂依赖关系处理需要更多手动配置。

  3. DevTools 成熟度:urql DevTools 功能相对基础,不如 Apollo DevTools 完善。在复杂缓存调试、性能分析等方面可能不够用。

  4. 缺乏内建分页/无限滚动抽象:Apollo Client 提供了 fetchMoreupdateQuery 等内建分页支持,urql 需要手动实现或通过 Exchange 扩展。

  5. React Server Components 集成仍在演进@urql/next 对 Next.js App Router 和 RSC 的支持仍在发展中,部分边缘场景可能需要自行处理。

  6. 单向数据流约束:urql 的 Exchange 管道是单向的,某些需要双向通信的场景(如复杂的订阅重连逻辑)实现起来较为复杂。

  7. 文档和示例覆盖不足:部分高级用法(如复杂 Exchange 编写、graphcache 高级配置)的文档和示例不够详尽。

迁移注意事项

从 Apollo Client 迁移到 urql 时需要注意:

  • Apollo 的 cache.modifycache.readQuerycache.writeQuery 等 API 在 urql 中没有直接对等物,需要通过 graphcache 的 updates 配置实现类似效果
  • Apollo 的 InMemoryCache 配置项(如 typePoliciesfieldPolicies)需要转换为 graphcache 的 keysupdatesresolvers 配置
  • Apollo 的 RefetchQueries 模式在 urql 中通过 cache.invalidate + requestPolicy: 'network-only' 实现

学习资源

官方资源

文章与教程

视频

社区


2026 年现状

版本演进

截至 2026 年 7 月,urql 生态系统已经历了多次重大版本迭代:

时间事件
2019 年Formidable Labs 发布 urql v1
2021 年v3 发布,转向 ES2015+
2023 年 3 月v4 发布,移除 IE11 支持,严格化 TypeScript 泛型
2025 年 9 月urql v5.0.0 发布,核心包升级到 v6
2026 年 7 月urql v5.0.3 / @urql/core v6.0.3(最新)

当前定位

urql 在 2026 年的 GraphQL 客户端生态中定位为:

  • 轻量替代方案:当 Apollo Client 过于臃肿时的首选替代
  • 多框架统一方案:唯一真正提供 React/Vue/Svelte/Solid/Preact 统一核心的成熟 GraphQL 客户端
  • 可定制性标杆:Exchange 架构提供了 GraphQL 客户端中最强的可定制能力

发展趋势

  1. 持续活跃开发:GitHub 上持续有提交和 Issue 处理,核心团队保持活跃
  2. Next.js 深度集成@urql/next 持续跟进 Next.js 最新版本(App Router、Turbopack 等)
  3. 类型安全增强:配合 graphql-codegen 的类型推导体验持续改善
  4. 性能持续优化:如最近的 perf: don't serialize data to IDB 等性能优化持续进行中
  5. 社区稳定增长:虽然增长速度不如 Apollo,但社区质量和贡献者活跃度保持稳定

是否值得采用?

推荐采用的场景

  • 新项目且团队偏好轻量方案
  • 多框架 Monorepo
  • Bundle size 有严格要求
  • 需要深度定制请求管道

需要谨慎的场景

  • 团队 GraphQL 经验有限,需要开箱即用的完整方案(Apollo 更合适)
  • 超大规模应用,需要最成熟的缓存和 DevTools 支持
  • 强依赖 cache.modify 等高级缓存操作

总结:urql 是 GraphQL 客户端生态中"少即是多"理念的最佳实践。它用 Exchange 管道这一优雅架构,在保持极小体积的同时提供了强大的可扩展性。对于追求轻量、灵活和多框架一致性的团队,urql 是 Apollo Client 之外最值得考虑的选择。