Learn GraphQL - React Native & Mobile Integration
Episode 28 of 51

Learn GraphQL - React Native & Mobile Integration

Episode 28 brings GraphQL to mobile: Apollo Client in React Native with AsyncStorage persistence, offline-first architecture with a mutation queue and synchronization, performance optimization for mobile networks, and Flutter integration with the graphql_flutter package.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Mobile is the main reason GraphQL was created — Facebook built it for bandwidth-efficient iOS apps. Episode 28 brings GraphQL into the mobile world with React Native and Flutter.

We'll build Apollo Client in React Native, persist the cache to AsyncStorage, design an offline-first architecture with a mutation queue, optimize performance for mobile networks, and close with Flutter integration.

React Native Setup

Apollo Client in React Native

Apollo Client runs in React Native almost exactly like on the web. The difference: networking and storage configuration are platform-adapted. Install with npm install @apollo/client graphql @react-native-async-storage/async-storage:

JSApollo Client with persistence
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { AsyncStorageWrapper, persistCache } from "apollo3-cache-persist";
import AsyncStorage from "@react-native-async-storage/async-storage";
 
const cache = new InMemoryCache();
 
persistCache({
  cache,
  storage: new AsyncStorageWrapper(AsyncStorage),
});
 
export const client = new ApolloClient({
  link: createHttpLink({ uri: "https://api.kalian.com/graphql" }),
  cache,
});

AsyncStorage persists the cache to the device's local storage. The result: previously loaded data stays available when the app is reopened, and users don't have to wait for the network to see data they've already loaded.

Network Configuration

Use an API URL accessible from the device — localhost on an emulator doesn't point to the developer's machine. For development, pay attention to the Android emulator and iOS simulator configurations. Avoid storing tokens in AsyncStorage without encryption; use secure storage like react-native-keychain for refresh tokens.

Offline-First Architecture

Offline Mutation Queue

An offline-first architecture means the app still works without a connection. The core concept: mutations that fail because of offline status go into a queue, processed when the connection returns:

JSOffline mutation queue
import { from, Observable } from "rxjs";
 
function createOfflineQueueLink() {
  const queue = [];
  return from(new Observable((observer) => {
    if (navigator.onLine) {
      return forward(operation).subscribe(observer);
    }
    queue.push(operation);
    observer.complete();
  }));
}

When the connection recovers, replay the entire queue in order (mutations execute serially, episode 5). Add an idempotency key to mutations so replayed operations don't create duplicate data.

Optimistic UI and Sync

Optimistic UI becomes even more important on mobile: while offline, show changes immediately based on optimisticResponse, then sync when the real response arrives. For conflict resolution when two devices change the same data, apply strategies like last-write-wins or per-field versions — the details are covered in episode 38.

Performance Optimization

Query Batching and Bundle Size

Mobile networks are expensive and unstable. Required optimizations:

  • Query batching: combine several operations into one HTTP request to reduce round-trips.
  • APQ: use Automatic Persisted Queries (episode 19) so payloads shrink on slow networks.
  • Fragments and caching: reduce refetching with fragments that leverage the cache (episode 4).
JSReduce the bundle with selective imports
import { ApolloClient, InMemoryCache } from "@apollo/client";

Avoid importing whole libraries; use selective imports and code splitting so the React Native bundle stays small. For images, serve them through a CDN at device-appropriate sizes.

Network-Aware Queries

Adapt behavior to network conditions: reduce polling when the app is in the background, increase the cache size on Wi-Fi, and show cached data first (cache-first) on slow networks. Detect connectivity with @react-native-community/netinfo and change fetchPolicy dynamically.

Flutter Integration

graphql_flutter

For Flutter, the community's official package is graphql_flutter:

pubspec.yaml
dependencies:
  graphql_flutter: ^5.1.0
JSgraphql_flutter setup
import 'package:graphql_flutter/graphql_flutter.dart';
 
final client = GraphQLClient(
  link: HttpLink('https://api.kalian.com/graphql'),
  cache: GraphQLCache(store: HiveStore()),
);

Queries and mutations are done via widgets or extensions:

JSQuery in Flutter
Query(
  options: QueryOptions(
    document: gql('''
      query GetUser(\$id: ID!) {
        user(id: \$id) { id username }
      }
    '''),
    variables: {'id': userId},
  ),
  builder: (result, {fetchMore, refetch}) {
    if (result.isLoading) return Text('Memuat...');
    return Text(result.data!['user']['username']);
  },
)

graphql_flutter also supports subscriptions and cache persistence with Hive — enough to build full-stack GraphQL Flutter apps using the same patterns as React Native.

Conclusion

Key takeaways:

  • Apollo Client in React Native uses AsyncStorage for cache persistence.
  • Offline-first architecture queues mutations while offline and processes them when online.
  • Optimistic UI and idempotency keys keep synchronization stable on unreliable networks.
  • Batching, APQ, and code splitting save mobile bandwidth and bundle size.
  • graphql_flutter brings full GraphQL to Flutter with Hive caching.

In the next episode, episode 29, you'll learn about the GraphQL tooling ecosystem — schema visualization and design tools, API testing tools like Apollo Studio Explorer and Insomnia, schema management with GraphQL Inspector, IDE extensions, CLI tools, and mock servers. Your GraphQL development workflow will be far more productive!

Learn GraphQL - React Native & Mobile Integration | Learn GraphQL