Back to writing
Original post by Gagan Deep Singh, canonical on thegdsks.comAlso on Dev.toDiscuss on Dev.to

We Cut 70% Bundle Size: TanStack Query + Zustand at GLINR

From Apollo's 50kb to 18kb total - Our migration journey with architecture diagrams

4 min read

title: We Cut 70% Bundle Size: TanStack Query + Zustand at GLINR published: true description: From Apollo's 50kb to 18kb total - Our migration journey with architecture diagrams tags: react, javascript, webdev, architecture cover_image: https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=1200#

The Problem: Complexity Without Benefits#

Three months ago at GLINR, our AI-powered developer platform was shipping 50kb of Apollo Client just to fetch billing quotas and user data.

As the lead architect (GDSKS here), I kept asking: "Are we actually using these features?" The answer was uncomfortable: we were using about 10% of what Apollo offered.

What We Actually Needed#

Image description

The Metrics That Made Us Act#

Metric Value Status
Apollo Bundle 50kb gzipped Too large
Cache Complexity High Unused
Time to Interactive 2.8 seconds Slow
Developer Confidence 6.2/10 Low
Features Used ~10% Wasteful

The Solution: Architectural Separation#

The breakthrough came from a simple realization: server state and client state are fundamentally different.

The Core Principle#

Image description

State Classification#

State Type Characteristics Best Tool Example
Server State Asynchronous, cached, needs sync TanStack Query API data, user info, billing
Client State Synchronous, local, ephemeral Zustand Modals, themes, form wizards

Architecture Deep Dive#

Before: The Apollo Monolith#

Image description

Pain Points:

  • Mixed responsibilities (server + client state)
  • Unclear patterns for UI state
  • Complex cache invalidation
  • 50kb bundle for basic queries

After: Clean Separation#

Image description

Benefits:

  • Clear separation of concerns
  • Each tool optimized for its purpose
  • 18kb total bundle
  • Obvious patterns for developers

How Data Flows: The Complete Picture#

Query Lifecycle with TanStack Query#

Image description

State Updates with Zustand#

Image description


Real Implementation at GLINR#

The Code: Less Is More#

Here's the minimal code needed to get started:

Setup TanStack Query (5 lines):

tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: { queries: { staleTime: 60000 } }
});

// Wrap app

  

Setup Zustand (8 lines):

tsx
import { create } from 'zustand';

export const useAppStore = create((set) => ({
  activeOrgId: null,
  theme: 'light',
  setActiveOrg: (id) => set({ activeOrgId: id }),
  setTheme: (theme) => set({ theme }),
}));

Using Both Together:

tsx
// Component code
const { data: quotas } = useQuery({
  queryKey: ['quotas', orgId],
  queryFn: fetchQuotas
});

const { theme, setTheme } = useAppStore();

That's it. Seriously.


The Migration Journey#

Phase-by-Phase Approach#

Image description

Decision Tree for State Placement#

Image description


Production Results: The Numbers#

Performance Gains#

Image description

Developer Experience Impact#

Metric Before After Change
Time to add feature 4-6 hours 1-2 hours 67% faster
Developer confidence 6.2/10 9.1/10 47% increase
Code review time 45 min avg 20 min avg 56% faster
Onboarding new devs 2 weeks 3 days 80% faster

Cache Performance#

Image description

Image description


Architecture Patterns We Learned#

Store Organization#

Image description

Query Key Strategy#

Image description


When To Make This Switch#

Decision Matrix#

Image description

Good Fit Scenarios#

Scenario Recommendation Why
Simple GraphQL fetching Migrate TanStack Query is lighter, simpler
Building SPAs or dashboards Migrate Better cache control, less overhead
Team struggles with Apollo Migrate Much easier mental model
Need normalized caching Stay Apollo's strength
Heavy GraphQL subscriptions Stay Built-in support

Key Takeaways#

The Three Principles#

Image description

Best Practices Checklist#

  • Separate server state from client state
  • Use hierarchical query keys
  • Keep Zustand stores focused and small
  • Leverage TanStack Query's automatic caching
  • Use TypeScript for type safety
  • Set reasonable staleTime values
  • Enable DevTools during development
  • Monitor bundle size regularly

Resources & Next Steps#

Official Documentation#

Community & Support#

Further Reading#

  • "Goodbye Redux? Meet TanStack Query" - Industry shift analysis
  • "TanStack Start vs Next.js" - Framework comparison
  • "Modern React Patterns 2025" - Current best practices

About GLINR & GLINCKER#

GLINR is our AI-powered developer platform offering:

  • Profanity detection with AI enhancement
  • Text summarization via GCP NLP
  • URL shortening and QR generation
  • AI assistant services (upcoming)

GLINCKER is our parent brand building practical AI micro-tools for developers and businesses.


Connect & Follow#

Topics I write about:

  • Modern React architecture
  • Full-stack development patterns
  • AI/ML integration strategies
  • Developer productivity
  • Building scalable platforms

Share Your Experience#

Have you migrated from Apollo? Using TanStack Query + Zustand in production? Share your story in the comments below.

Found this helpful? Please share with your team and clap if you enjoyed the read.


This article is part of the GLINCKER Engineering Series. More coming on Next.js 15 patterns, Spring Boot 3 architecture, and building AI-powered SaaS platforms on limited resources.


Tags: #React #StateManagement #TanStackQuery #Zustand #WebDevelopment #JavaScript #TypeScript #Architecture #Apollo #GraphQL #NextJS #Frontend #Performance #2025


Published by GDSKS • Lead Architect, Founder at GLINCKER • Building GLINR Platform

Last updated: November 2025

This article is published here first and cross-posted to Dev.to. This page is the canonical version.
Contact