Vucense

React State Management 2026: Zustand vs Jotai vs TanStack Query

🟡Intermediate

Choose the right state management for React 2026: Zustand for global state, Jotai for atomic state, TanStack Query for server state — with real-world local-first code examples and browser performance tuning.

React State Management 2026: Zustand vs Jotai vs TanStack Query
Article Roadmap

Key Takeaways

  • Use Zustand for global client state, Jotai for local atomic and derived state, and TanStack Query for server-synced data — each tool excels in a different area of React 2026.
  • This guide includes a local-first React app architecture with Vite, secure state hydration, offline patterns, mutation pipelines, derived state, and performance tuning for browser-based UIs.
  • SovereignScore: 96/100 — the patterns emphasize local control, open-source packages, and minimized remote data dependencies through smart caching.

Direct Answer: Use Zustand when you need a fast, minimal global store for authenticated user state, feature flags, and client-side UI preferences. Use Jotai when you need fine-grained atomic state and derived selectors for complex local form state, dashboards, or isolated widgets. Use TanStack Query when you need server-state caching, background refresh, offline support, and mutation pipelines for REST or GraphQL data.

This article explains how to combine all three in a local-first React stack, with example code, performance guidance, and browser-based state validation.


Why React State Management Still Matters in 2026

React is no longer just a UI library; a modern React application is a full state machine that must coordinate:

  • local UI state and component interactions
  • persisted preferences and local caches
  • server-synced lists, pagination, and mutation flows
  • derived values and cross-component selectors
  • offline-first behavior and resilient browser caching

In sovereign applications, you also want strong local control over where state is stored, how it is refreshed, and how much data is sent over the network. The right toolkit can make the difference between an app that is maintainable and one that devolves into global state spaghetti.

What This Guide Covers

  • Installing the local React toolchain on Ubuntu 24.04
  • Designing a hybrid state architecture with Zustand, Jotai, and TanStack Query
  • Building a sample dashboard app that is local-first and network-aware
  • Optimizing state updates, selectors, and derived state
  • Using local caching, persistence, and offline fallbacks
  • Handling optimistic updates and error recovery
  • Benchmarking browser performance and avoiding React re-render pitfalls
  • Governance patterns for state consistency and auditability

1. Setup: Local React Toolchain on Ubuntu 24.04

Install Node, pnpm, and Vite locally

sudo apt update
sudo apt install -y curl git build-essential libssl-dev
curl -fsSL https://get.pnpm.io/install.sh | sh -
source ~/.bashrc
pnpm env use --global stable
pnpm --version

Create the React app scaffold

mkdir -p ~/react-state-management-2026
cd ~/react-state-management-2026
pnpm create vite . --template react-ts
pnpm install

Add the state management dependencies

pnpm add zustand jotai @tanstack/react-query @tanstack/query-core axios
pnpm add -D vitest @testing-library/react @testing-library/jest-dom

Confirm the environment

pnpm exec node -v
pnpm exec tsc --noEmit
pnpm exec vite --version

This sets up a local-first React development environment without cloud-provisioned tooling.


2. Compare the Tools: What Each One is Best For

Zustand: Global and persistent client state

Zustand is ideal for:

  • lightweight global state stores
  • app-wide preferences and feature flags
  • authentication tokens and user profiles
  • non-server state that must be shared across screens

Strengths:

  • tiny API surface
  • no React context overhead when using selectors
  • supports middleware for persistence and logging

Limitations:

  • not optimized for server caching
  • subscription semantics are explicit and need careful selector design

Jotai: Atomic, derived, and isolated state

Jotai is ideal for:

  • local form state and wizard flows
  • derived state with fine-grained dependency tracking
  • isolated widgets, tabs, and canvas controls
  • state that should not all live in one global store

Strengths:

  • atomic model avoids monolithic stores
  • derived atoms are recomputed only when needed
  • excellent for composable state logic

Limitations:

  • can be overkill for simple app-level flags
  • mental model is different from typical Redux/Zustand apps

TanStack Query: Server state and background sync

TanStack Query is ideal for:

  • fetching lists, paginated data, and entity queries
  • caching server responses and invalidating stale data
  • optimistic updates and mutation retries
  • offline support and background refetching

Strengths:

  • declarative data fetching hooks
  • built-in caching, deduping, and stale-while-revalidate patterns
  • excellent developer ergonomics for server state

Limitations:

  • not designed for purely client-local UI state
  • works best when you have a stable remote data contract

3. Application Architecture: Hybrid State for Sovereign React Apps

A mature React app often uses multiple state systems together. Here is the recommended architecture:

  • Zustand for global local state and cross-cutting concerns
  • Jotai for isolated, derived UI state inside widgets and forms
  • TanStack Query for all server-synced data and remote cache
  • Local storage or IndexedDB for persistent local preferences and offline cache

Example app structure

src/
  app/
    store.ts       # Zustand global state
    atoms.ts       # Jotai atoms and derived state
    queryClient.ts # TanStack Query client
  features/
    auth/
    dashboard/
    settings/
  components/
    Header.tsx
    Sidebar.tsx
    TaskTable.tsx

This separation keeps each state concern in the tool that handles it best.


4. Zustand: Global Store with Persistence and Devtools

4.1 Create the global store

src/app/store.ts:

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

type AppState = {
  theme: 'light' | 'dark';
  user: { id: string; name: string } | null;
  sidebarOpen: boolean;
  setTheme: (theme: 'light' | 'dark') => void;
  setUser: (user: AppState['user']) => void;
  toggleSidebar: () => void;
};

export const useAppStore = create<AppState>()(
  persist(
    (set) => ({
      theme: 'light',
      user: null,
      sidebarOpen: true,
      setTheme: (theme) => set({ theme }),
      setUser: (user) => set({ user }),
      toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
    }),
    {
      name: 'vucense-app-state',
      partialize: (state) => ({ theme: state.theme, sidebarOpen: state.sidebarOpen }),
    }
  )
);

This store persists only UI preferences locally while keeping sensitive user data out of persisted storage if you choose.

4.2 Use Zustand selectors to minimize re-renders

In a component:

import { useAppStore } from '../app/store';

const SidebarToggle = () => {
  const [sidebarOpen, toggleSidebar] = useAppStore((state) => [state.sidebarOpen, state.toggleSidebar]);
  return <button onClick={toggleSidebar}>{sidebarOpen ? 'Close' : 'Open'} sidebar</button>;
};

This selector pattern ensures only components that care about sidebarOpen re-render.

4.3 Add middleware for logging and hydration

Zustand middleware can log state changes and integrate with local dev tools:

import { devtools } from 'zustand/middleware';

export const useAppStore = create<AppState>()(
  devtools(
    persist((set) => ({ ... }), { name: 'vucense-app-state' }),
    { name: 'VucenseAppStore' }
  )
);

Use this for local debugging without external telemetry.

4.4 When not to use Zustand

Do not store server-synced lists or entity caches in Zustand. TanStack Query handles caching, stale data, and invalidation more reliably.


5. Jotai: Atomic State for Forms and Derived Values

Jotai shines when state is naturally local or when you need derived state with minimal re-render churn.

5.1 Create atoms for a complex form

src/app/atoms.ts:

import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';

export const firstNameAtom = atom('');
export const lastNameAtom = atom('');
export const emailAtom = atom('');

export const fullNameAtom = atom((get) => {
  const first = get(firstNameAtom);
  const last = get(lastNameAtom);
  return `${first} ${last}`.trim();
});

export const preferencesAtom = atomWithStorage('vucense-preferences', { language: 'en', timezone: 'UTC' });

This atomic model cleanly separates fields and derived values.

5.2 Use atoms in components

import { useAtom } from 'jotai';
import { firstNameAtom, lastNameAtom, fullNameAtom } from '../app/atoms';

const ProfileForm = () => {
  const [firstName, setFirstName] = useAtom(firstNameAtom);
  const [lastName, setLastName] = useAtom(lastNameAtom);
  const [fullName] = useAtom(fullNameAtom);

  return (
    <div>
      <input value={firstName} onChange={(e) => setFirstName(e.target.value)} placeholder="First name" />
      <input value={lastName} onChange={(e) => setLastName(e.target.value)} placeholder="Last name" />
      <p>Full name: {fullName}</p>
    </div>
  );
};

Because atoms are independent, only the inputs that actually change will re-render.

5.3 Use derived atoms for computed state

Derived atoms help avoid recalculating values in every render:

export const totalTasksAtom = atom((get) => get(taskListAtom).length);

Use this for charts, summaries, and local dashboard logic.

5.4 Local storage and persistence with atomWithStorage

For sovereign apps, use local storage or IndexedDB to persist user preferences.

export const themeAtom = atomWithStorage<'light' | 'dark'>('vucense-theme', 'light');

This keeps the values on the client and does not require remote persistence.

5.5 When not to use Jotai

Avoid using Jotai for server state unless you have a very narrow, widget-specific requirement. TanStack Query is better suited for remote data that must be cached and refreshed.


6. TanStack Query: Server State, Caching, and Offline Synchronization

TanStack Query is the best fit for all server-synced data.

6.1 Create the query client

src/app/queryClient.ts:

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

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 2,
      cacheTime: 1000 * 60 * 30,
      retry: 1,
      refetchOnWindowFocus: false,
      refetchOnReconnect: true,
    },
    mutations: {
      retry: false,
    },
  },
});

6.2 Wrap the app with QueryClientProvider

src/main.tsx:

import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from './app/queryClient';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>
);

6.3 Fetch server data with useQuery

src/features/dashboard/useTasks.ts:

import axios from 'axios';
import { useQuery } from '@tanstack/react-query';

export type Task = { id: string; title: string; completed: boolean; };

const fetchTasks = async (): Promise<Task[]> => {
  const resp = await axios.get('/api/tasks');
  return resp.data;
};

export const useTasks = () => {
  return useQuery(['tasks'], fetchTasks, {
    staleTime: 1000 * 60,
    cacheTime: 1000 * 60 * 10,
    retry: 2,
  });
};

6.4 Use the query in a component

import { useTasks } from './useTasks';

const TaskList = () => {
  const { data, isLoading, error } = useTasks();

  if (isLoading) return <div>Loading tasks...</div>;
  if (error) return <div>Error loading tasks.</div>;

  return (
    <ul>{data.map((task) => <li key={task.id}>{task.title}</li>)}</ul>
  );
};

6.5 Mutations and optimistic updates

src/features/dashboard/useTaskMutations.ts:

import { useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';

const updateTask = async (task: Task) => {
  const resp = await axios.put(`/api/tasks/${task.id}`, task);
  return resp.data;
};

export const useUpdateTask = () => {
  const queryClient = useQueryClient();

  return useMutation(updateTask, {
    onMutate: async (updatedTask) => {
      await queryClient.cancelQueries(['tasks']);
      const previous = queryClient.getQueryData<Task[]>(['tasks']);
      queryClient.setQueryData<Task[]>(['tasks'], (old) =>
        old?.map((task) => (task.id === updatedTask.id ? updatedTask : task)) ?? []
      );
      return { previous };
    },
    onError: (_err, _vars, context) => {
      if (context?.previous) {
        queryClient.setQueryData(['tasks'], context.previous);
      }
    },
    onSettled: () => {
      queryClient.invalidateQueries(['tasks']);
    },
  });
};

This pattern gives local-first responsiveness while still reconciling with the server.

6.6 Offline support with cached queries

TanStack Query can continue to show cached data when offline. Use react-query persistence with localStorage or IndexedDB.

pnpm add @tanstack/react-query-persist-client @tanstack/query-sync-storage-persister

Set up persistence in src/app/queryClient.ts:

import { persistQueryClient } from '@tanstack/react-query-persist-client';
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';

const persister = createSyncStoragePersister({
  storage: window.localStorage,
});

persistQueryClient({
  queryClient,
  persister,
  maxAge: 1000 * 60 * 60 * 24,
});

This helps the browser remain useful when the network is unavailable.


7. Building a Local-First Dashboard Example

The best way to understand these tools together is a practical example.

7.1 App concept

Build a local dashboard that shows:

  • current user profile from Zustand
  • server-synced task list with TanStack Query
  • local filters and derived counts with Jotai
  • theme and layout state persisted in Zustand

7.2 Global store and query client wiring

src/App.tsx:

import { useAppStore } from './app/store';
import { useTasks } from './features/dashboard/useTasks';
import { useAtom } from 'jotai';
import { filterAtom, filteredTasksAtom } from './app/atoms';

const App = () => {
  const theme = useAppStore((state) => state.theme);
  const toggleSidebar = useAppStore((state) => state.toggleSidebar);
  const { data: tasks } = useTasks();
  const [filter, setFilter] = useAtom(filterAtom);
  const [filteredTasks] = useAtom(filteredTasksAtom);

  return (
    <div className={theme === 'dark' ? 'theme-dark' : 'theme-light'}>
      <header>
        <button onClick={toggleSidebar}>Toggle Sidebar</button>
      </header>
      <main>
        <div>
          <label>
            Filter:
            <input value={filter} onChange={(e) => setFilter(e.target.value)} />
          </label>
        </div>
        <TaskTable tasks={filteredTasks} />
      </main>
    </div>
  );
};

7.3 Derived filters with Jotai

src/app/atoms.ts addition:

export const filterAtom = atom('');
export const taskListAtom = atom<Task[]>([]);

export const filteredTasksAtom = atom((get) => {
  const filter = get(filterAtom).toLowerCase();
  const tasks = get(taskListAtom);
  return tasks.filter((task) => task.title.toLowerCase().includes(filter));
});

Sync the query result into the atom only when tasks change:

const TaskContainer = () => {
  const { data: tasks } = useTasks();
  const [, setTaskList] = useAtom(taskListAtom);

  useEffect(() => {
    if (tasks) setTaskList(tasks);
  }, [tasks, setTaskList]);

  return <TaskTable />;
};

This hybrid pattern combines server state and local derived state cleanly.

7.4 Local-first failure UI

When the network is unavailable, use cached query data and show offline hints:

const { data, isFetching, isError, error } = useTasks();

if (isError) {
  return <div>Unable to refresh tasks. Showing cached data if available.</div>;
}

Keep the app usable even if remote fetch fails.


8. Advanced State Patterns and Performance Tuning

8.1 Normalize server state

When your server returns nested entities, normalize them before storing or feeding into components. This reduces unnecessary re-renders and makes updates easier.

TanStack Query is good for caching raw server responses, but you can also use utility functions to normalize large lists.

8.2 Use shallow equality on Zustand selectors

For complex selector arrays:

const [theme, sidebarOpen] = useAppStore(
  (state) => [state.theme, state.sidebarOpen],
  shallow
);

This prevents re-render churn when unrelated state changes.

8.3 Prefer derived atoms over expensive selectors

In Jotai, derived atoms memoize automatically. Use them for expensive computations such as aggregated dashboard metrics.

8.4 Avoid storing ephemeral UI state in persisted storage

Persist only stable preferences. Avoid persisting fast-changing UI state such as hover targets, open dropdowns, or transient widgets.

8.5 Use react-query suspense carefully

If you enable suspense mode with TanStack Query, wrap components in an error boundary and a fallback UI.


9. Local Caching and Persistence Strategies

A sovereign React app should keep client state local where possible.

9.1 Persist UI preferences with Zustand middleware

Use persist and selectively store only the safe fields.

9.2 Persist query cache for offline reads

Use the TanStack Query persister with localStorage or IndexedDB.

9.3 Cache static reference data in Jotai

Atoms are great for reference lists that rarely change, like country codes or UI options.

9.4 Use local fallback data in absence of network

const tasksFallback = [{ id: 'offline-1', title: 'Offline task', completed: false }];

Use these local values only as a fallback when the network and cache are unavailable.


10. State Testing and Validation

Testing state logic is critical for maintainable React applications.

10.1 Test Zustand selectors and actions

Use unit tests for store actions:

import { act } from 'react-dom/test-utils';
import { useAppStore } from './store';

it('toggles sidebar', () => {
  const { result } = renderHook(() => useAppStore((state) => state.sidebarOpen));
  act(() => useAppStore.getState().toggleSidebar());
  expect(result.current).toBe(false);
});

10.2 Test Jotai atoms

Use renderHook with Provider:

import { Provider, useAtom } from 'jotai';

const useName = () => useAtom(firstNameAtom);

10.3 Test TanStack Query hooks

Use QueryClientProvider with mock axios responses.

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

10.4 Use component tests for state-driven UI

Test the Dashboard component with mocked server lists and atom values.


11. Migrating Existing React Apps to the Hybrid State Model

If you already have a legacy global store, migrate incrementally.

11.1 Extract feature slices to Jotai

Move widget-local state into atoms before refactoring the global store.

11.2 Replace server cache in Redux with TanStack Query

Start by using useQuery for one endpoint and keep the old store until the new flows are stable.

11.3 Move app settings into Zustand

Keep the existing store for the rest of the app while migrating theme, locale, and UI preferences into Zustand.

11.4 Understand your state boundary

A useful rule of thumb:

  • if state is derived from the server, use TanStack Query
  • if state belongs to a single component/widget, use Jotai
  • if state is truly global and persistent, use Zustand

12. Toolchain Validation and Local Performance Benchmarks

Measure browser performance locally to verify your state design.

12.1 Use Vite build profiling

Run:

pnpm exec vite build --profile

Inspect bundle size and note the cost of state libraries.

12.2 Use React profiler in the browser

Open DevTools Profiler, record an interaction, and inspect which components render when state changes.

12.3 Benchmark state updates

Compare a global re-render with a selector-based update. If a component re-renders unexpectedly, refine the selector or split the state.

12.4 Use local network simulation

Simulate slow connections with the browser network throttling panel to verify offline and stale caching behavior.


13. Security and Sovereignty Considerations for React State

A local-first React app should treat state as part of the sovereign boundary.

13.1 Keep sensitive state out of persisted stores

Do not persist authentication tokens or PII in localStorage unless encrypted and explicitly authorized.

13.2 Use secure storage for session state

If you need to persist tokens, keep them in secure HTTP-only cookies or encrypted IndexedDB abstractions.

13.3 Avoid remote state dependencies for UI preferences

Store UI preferences client-side in Zustand; do not sync them to a remote service unless necessary.

13.4 Audit state transitions in critical flows

For sovereign operations, log state transitions in a local dev console or optional debug overlay without sending telemetry externally.


14. Progressive Enhancement and Accessibility

React state management should support all devices and connection qualities.

14.1 Graceful fallback for missing browser APIs

If localStorage or IndexedDB is unavailable, use in-memory fallbacks and warn the user.

14.2 Keep server state accessible when JS is disabled

For public pages, prefer server-side rendering or a static fallback with hydration. Use TanStack Query on top of SSR if needed.

14.3 Use state to improve accessibility

Manage focus state, keyboard navigation, and form validation through atoms and derived state.


15. Packaging and Deployment for Local-First React Apps

15.1 Build the production bundle

pnpm exec vite build

15.2 Serve locally with a secure origin

pnpm exec vite preview --host 127.0.0.1 --port 4173

15.3 Include source maps for local debugging

Enable source maps in production builds only for internal deployments.


16. Component-Level Patterns for State Efficiency

16.1 Use memoized callbacks

const toggle = useCallback(() => setTheme(theme === 'dark' ? 'light' : 'dark'), [theme]);

16.2 Avoid anonymous selector objects

Pass stable selectors to Zustand to prevent unnecessary updates.

16.3 Keep derived values in Jotai or selectors

Compute expensive values once in an atom rather than inside every render.


17. Example: Real-Time Settings Panel

Build a settings panel that persists changes and reflects server-side defaults.

  • UI preferences in Zustand
  • feature toggles as atoms in Jotai
  • remote config loaded with TanStack Query

This pattern is common in local-first admin UIs.


18. Common Pitfalls and How to Avoid Them

18.1 Overusing global stores

If every bit of state lives in Zustand, you will lose the benefits of Jotai and TanStack Query.

18.2 Storing server state in local storage

Use TanStack Query caching and persistence, not manual snapshot storage.

18.3 Re-render storms

Use selectors and derived atoms to keep only the affected subtree updating.

18.4 Inconsistent mutation flows

Keep server mutations in TanStack Query and local UI state in Zustand or Jotai to avoid mixing concerns.


19. Monitoring and Debugging Local State

19.1 Add Zustand devtools locally

pnpm add -D zustand-middleware-devtools

19.2 Use Jotai debug hooks

Use useAtomDevTools or simple logging atoms in development builds.

19.3 Inspect TanStack Query cache

In the browser console, call queryClient.getQueryCache().findAll().


20. Final Recommendations for React State in 2026

  • Use Zustand for lightweight global state and persisted UI preferences.
  • Use Jotai for local atomic state and derived values inside widgets.
  • Use TanStack Query for server-synced remote data, caching, and mutation pipelines.
  • Keep each layer focused on a single responsibility.
  • Measure re-renders and optimize selectors early.
  • Persist only safe data locally and avoid over-serializing ephemeral state.
  • Keep the architecture simple for sovereign, local-first applications.

21. Advanced Orchestration: Split State by Load and Locality

Large applications benefit from splitting state by where it is loaded and how often it changes.

21.1 Hydration-aware state loading

For apps that render on the server or pre-render pages, make sure global state hydration is deterministic. Use Zustand with hydration handlers when server-rendering values such as theme or selected workspace.

21.2 Split local cache from live server data

Keep transient UI state in Jotai atoms and server-backed entities in TanStack Query. This avoids entangling the stable query cache with fast-changing form state.

21.3 Load state lazily by route

Use code splitting to load feature stores only when needed. For example, lazy-load a large settings module and its Zustand slice only when the user opens the settings route.

const SettingsPage = lazy(() => import('./features/settings/SettingsPage'));

21.4 Prefer event-driven state updates

Use local event handlers and atom updates instead of polling when the UI can respond immediately. TanStack Query can still refresh in the background while Jotai handles the interactive form state.

21.5 Keep state ownership explicit

Document which library owns each piece of state. A state map helps teams avoid moving the same data between Zustand, Jotai, and TanStack Query multiple times.

This advanced orchestration pattern enables sovereign React apps to scale without losing clarity or local-first control.


People Also Ask

What makes React State Management 2026: Zustand vs Jotai vs TanStack Query relevant for sovereign infrastructure in 2026?

This guide maps each state tool to the right problem space in a local-first React app. It shows how to keep UI state, derived widget state, and server data distinct while preserving local control and minimizing unnecessary remote dependencies.

Can I use Zustand and Jotai together in the same app?

Yes. Use Zustand for broad global state and Jotai for isolated or derived component state. The combination is powerful when each tool is used for its strengths.

When should I use TanStack Query instead of custom data fetching hooks?

Use TanStack Query when you need caching, stale data management, background refetching, retries, and mutation workflows. Custom fetch hooks are okay for simple one-off data loads, but TanStack Query handles most server-state patterns robustly.

How do I keep React state manageable in a large local-first dashboard?

Separate concerns: global app state in Zustand, local widget state in Jotai, server data in TanStack Query, and persistence in storage middleware. Keep the structure consistent across features and use typed selectors to avoid hidden dependencies.


Further Reading

Tested on: Ubuntu 24.04 LTS (Hetzner CX22). Last verified: May 2, 2026.

Anju Kushwaha

About the Author

Founder & Editorial Director

B-Tech Electronics & Communication Engineering | Founder of Vucense | Technical Operations & Editorial Strategy

Anju Kushwaha is the founder and editorial director of Vucense, driving the publication's mission to provide independent, expert analysis of sovereign technology and AI. With a background in electronics engineering and years of experience in tech strategy and operations, Anju curates Vucense's editorial calendar, collaborates with subject-matter experts to validate technical accuracy, and oversees quality standards across all content. Her role combines editorial leadership (ensuring author expertise matches topics, fact-checking and source verification, coordinating with specialist contributors) with strategic direction (choosing which emerging tech trends deserve in-depth coverage). Anju works directly with experts like Noah Choi (infrastructure), Elena Volkov (cryptography), and Siddharth Rao (AI policy) to ensure each article meets E-E-A-T standards and serves Vucense's readers with authoritative guidance. At Vucense, Anju also writes curated analysis pieces, trend summaries, and editorial perspectives on the state of sovereign tech infrastructure.

View Profile

Further Reading

All Dev Corner

Comments