What State Management Library Does Instatic Use? Zustand Implementation Deep Dive

Instatic uses Zustand, a minimal React state container, enhanced with the zustand-mutative middleware for immutable draft updates and subscribeWithSelector for performant subscriptions, to power its admin interface.

The CoreBunch/Instatic repository leverages Zustand as its primary state management library, implementing a slice-based architecture that supports direct state mutations through middleware while maintaining type safety across the visual editor and AI agent stores.

Core State Management Library Configuration

The global store definition resides in src/admin/pages/site/store/store.ts, where the application composes multiple domain slices into a single unified store. The configuration uses create from zustand wrapped in two critical middlewares:

  1. subscribeWithSelector from zustand/middleware – Enables efficient subscriptions to specific state slices
  2. mutative from zustand-mutative – Allows draft-style mutations that compile to immutable updates
// src/admin/pages/site/store/store.ts
import { create } from 'zustand';
import { mutative } from 'zustand-mutative';
import { subscribeWithSelector } from 'zustand/middleware';
import { siteSlice } from './slices/site';
import { settingsSlice } from './slices/settings';

export const useStore = create()(
  subscribeWithSelector,
  mutative,
  (set, get) => ({
    ...siteSlice(set, get),
    ...settingsSlice(set, get),
    // …other slices
  })
);

Slice Architecture with Mutative Updates

Each domain area defines its own TypeScript slice using the StateCreator type from Zustand. The siteSlice in src/admin/pages/site/store/slices/site/types.ts demonstrates the mutative pattern:

// src/admin/pages/site/store/slices/site/types.ts
import type { StateCreator } from 'zustand';
import type { Draft } from 'immer';

export type SiteState = {
  selectedNodeId: string | null;
  // …
};

export const siteSlice: StateCreator<SiteState, [['zustand/mutative', never]]> = (set) => ({
  selectedNodeId: null,
  selectNode: (id) =>
    set((state: Draft<SiteState>) => {
      state.selectedNodeId = id;      // mutable draft
    }),
});

The type annotation [['zustand/mutative', never]] marks the slice as mutative-enabled, allowing direct property assignment on the draft state while the middleware handles immutable updates under the hood.

React Integration and Performance Patterns

Components access the store through hooks that leverage useShallow from zustand/react/shallow to prevent unnecessary re-renders. The usePropertiesPanelData.ts utility in the PropertiesPanel illustrates this pattern:

// src/admin/pages/site/panels/PropertiesPanel/usePropertiesPanelData.ts
import { useStore } from '../../store/store';
import { useShallow } from 'zustand/react/shallow';

export const usePropertiesPanelData = () => {
  const { selectedNodeId, selectNode } = useStore(
    useShallow((s) => ({
      selectedNodeId: s.selectedNodeId,
      selectNode: s.selectNode,
    }))
  );
  
  return { selectedNodeId, selectNode };
};

For imperative access outside React components, the store exposes a getState() method directly on the Zustand instance, as implemented in src/admin/ai/useAgentStore.ts.

Build Configuration and Middleware Bundling

The Vite configuration in vite.config.ts explicitly treats zustand-mutative as a vendor dependency, ensuring proper code splitting and caching. This separation keeps the mutative middleware optimized and independently cacheable from application logic.

Summary

  • Zustand serves as the core state management library for Instatic's admin UI, providing a lightweight alternative to Redux or Context API.
  • The zustand-mutative middleware enables ergonomic draft-style mutations while preserving immutable update semantics, replacing Immer with a smaller bundle footprint.
  • Typed slices organize state by domain (site, settings, agents) using StateCreator with middleware type annotations.
  • useShallow selectors optimize React rendering performance by preventing component updates when unrelated state changes.
  • Key files: src/admin/pages/site/store/store.ts defines the global store, src/admin/state/workspaceLayout.ts contains UI-level stores, and src/admin/pages/site/store/slices/site/types.ts demonstrates the mutative slice pattern.

Frequently Asked Questions

Why did Instatic choose Zustand over Redux or Context API?

Zustand provides the global state capabilities required for a complex visual editor without Redux's boilerplate or Context API's performance limitations. The zustand-mutative middleware specifically allows the team to write mutable-style updates that compile to immutable changes, matching Immer's ergonomics while maintaining minimal bundle size.

How does the zustand-mutative middleware handle immutable updates?

The middleware intercepts mutations on draft objects and applies them as immutable updates behind the scenes. When slice writers call set((state) => { state.selectedNodeId = id }), the middleware creates a draft copy, applies the mutation, and returns a new immutable state to Zustand's store, ensuring React's change detection works correctly while allowing simpler syntax.

Can Instatic's Zustand store be accessed outside of React components?

Yes. The store exports a getState() method directly from the Zustand instance, enabling access in utility functions and AI agents. For example, useZustandStore.getState() returns the current state object without requiring React hooks, as implemented in files like src/admin/ai/useAgentStore.ts.

What is the purpose of subscribeWithSelector in Instatic's store?

subscribeWithSelector enables components to subscribe to specific state slices rather than the entire store. This middleware improves performance by ensuring callbacks only fire when selected portions of state change, rather than on any store update, which is critical for a high-frequency editor interface where components need granular state awareness.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →