# How to Access Zustand State Outside of React Components

> Learn how to access Zustand state outside React components. Explore using getState setState and subscribe methods from the store hook or create a vanilla store with createStore for greater flexibility.

- Repository: [Poimandres/zustand](https://github.com/pmndrs/zustand)
- Tags: how-to-guide
- Published: 2026-03-06

---

**You can access Zustand state outside React components by calling the static methods `getState()`, `setState()`, and `subscribe()` attached directly to the store hook, or by creating a vanilla store with `createStore()` from `zustand/vanilla`.**

Accessing Zustand state outside of React components is a core feature of the pmndrs/zustand library. Whether you need to read state from a utility module, update state from an API response handler, or subscribe to changes in a Node.js script, the store exposes a vanilla JavaScript API that operates independently of React's component lifecycle.

## The Store API Architecture

Zustand stores are created using either `create` (for React) or `createStore` (for vanilla JavaScript). Both functions return **an API object** containing four core utilities:

- `getState` – returns the current state snapshot
- `setState` – updates the state via shallow merge by default
- `subscribe` – registers a listener for state changes
- `getInitialState` – returns the state at store creation time

In [`src/vanilla.ts`](https://github.com/pmndrs/zustand/blob/main/src/vanilla.ts), these utilities are defined as the core store implementation (`setState` at lines 66-80, `getState` at line 83, and `subscribe` at lines 88-92). When you use `create` in [`src/react.ts`](https://github.com/pmndrs/zustand/blob/main/src/react.ts), the hook is built and the API is mixed into it using `Object.assign` (lines 56-58), making these methods available directly on the exported hook.

Because the hook carries these static methods, you can call them anywhere—in plain JavaScript modules, utility functions, event listeners, or Node scripts—without importing React.

## Reading and Writing State Outside Components

### Retrieve Current State with getState()

To read the latest state snapshot non-reactively, call `getState()` directly on the store hook. This returns the current value without subscribing to future updates.

```typescript
// counterStore.ts
import { create } from 'zustand';

export const useCounterStore = create<{
  count: number;
  inc: () => void;
}>()((set) => ({
  count: 0,
  inc: () => set((s) => ({ count: s.count + 1 })),
}));

// utility.ts - outside any React component
import { useCounterStore } from './counterStore';

// Get current count (non-reactive snapshot)
const currentCount = useCounterStore.getState().count;
console.log(currentCount); // → 0

```

### Update State with setState()

Use `setState()` to update the store from outside React. You can pass a partial state object for shallow merging or an updater function that receives the current state.

```typescript
import { useCounterStore } from './counterStore';

// Shallow merge update
useCounterStore.setState({ count: 10 });

// Functional update based on previous state
useCounterStore.setState((state) => ({ count: state.count + 5 }));

// Replace entire state (second argument = true)
useCounterStore.setState({ count: 0 }, true);

```

### Subscribe to State Changes

The `subscribe` method listens to every state change and executes a callback. It returns an unsubscribe function that you must call to prevent memory leaks.

```typescript
import { useCounterStore } from './counterStore';

// Subscribe to all changes
const unsubscribe = useCounterStore.subscribe((state) => {
  console.log('Counter changed:', state.count);
});

// Later, cleanup the subscription
unsubscribe();

```

## Using Vanilla Stores for Non-React Contexts

When you need a store that has no React dependencies—such as for Node.js scripts, shared logic across multiple React roots, or framework-agnostic modules—use `createStore` from `zustand/vanilla`. This exports the underlying vanilla implementation defined in [`src/vanilla.ts`](https://github.com/pmndrs/zustand/blob/main/src/vanilla.ts) (lines 99-101) without the React binding.

```typescript
// vanillaStore.ts
import { createStore } from 'zustand/vanilla';

export const counterStore = createStore<{
  count: number;
  inc: () => void;
}>((set) => ({
  count: 0,
  inc: () => set((s) => ({ count: s.count + 1 })),
}));

// Extract methods for convenience
export const { getState, setState, subscribe } = counterStore;

// usage.ts - Node.js script or vanilla JS module
import { getState, setState, subscribe } from './vanillaStore';

console.log('Initial:', getState().count); // 0

setState({ count: 42 });
console.log('Updated:', getState().count); // 42

const off = subscribe((state) => console.log('Changed:', state));
setState({ count: 100 }); // triggers listener
off(); // cleanup

```

## Advanced Subscriptions with Selectors

For performance-critical scenarios outside React, you can subscribe to specific slices of state rather than every change using the `subscribeWithSelector` middleware from `zustand/middleware`. This allows you to provide a selector function and an equality function to control when the callback fires.

```typescript
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';

export const useTodoStore = create(
  subscribeWithSelector((set) => ({
    todos: [] as string[],
    add: (t: string) => set((s) => ({ todos: [...s.todos, t] })),
  }))
);

// Subscribe to specific property changes outside React
const unsubscribe = useTodoStore.subscribe(
  (state) => state.todos.length, // selector
  (length, prevLength) => {
    console.log(`Todo count changed from ${prevLength} to ${length}`);
  },
  { equalityFn: (a, b) => a === b } // optional equality check
);

useTodoStore.getState().add('Buy milk'); // triggers callback
unsubscribe();

```

## Summary

- **Static methods on the hook**: The `create` function returns a hook with `getState`, `setState`, `subscribe`, and `getInitialState` attached directly, enabling access outside React components.
- **Core implementation**: These methods are defined in [`src/vanilla.ts`](https://github.com/pmndrs/zustand/blob/main/src/vanilla.ts) and attached to the React hook in [`src/react.ts`](https://github.com/pmndrs/zustand/blob/main/src/react.ts) via `Object.assign`.
- **Vanilla stores**: Import `createStore` from `zustand/vanilla` to create React-agnostic stores suitable for Node.js or shared logic.
- **Selective subscriptions**: Use the `subscribeWithSelector` middleware to listen to specific state slices rather than all changes.
- **Memory management**: Always store and call the unsubscribe function returned by `subscribe` to prevent memory leaks when components or modules unmount.

## Frequently Asked Questions

### Can I use Zustand without React at all?

Yes. Import `createStore` from `zustand/vanilla` to create a standalone store that has zero React dependencies. This is implemented in [`src/vanilla.ts`](https://github.com/pmndrs/zustand/blob/main/src/vanilla.ts) and exports the same `getState`, `setState`, and `subscribe` utilities without the hook wrapper used in [`src/react.ts`](https://github.com/pmndrs/zustand/blob/main/src/react.ts).

### How do I get the initial state of a store outside a component?

Call `getInitialState()` on the store hook or vanilla store instance. This method returns the state as it existed when the store was first created, useful for resetting state or testing purposes.

### Is getState() reactive like the useStore hook?

No. `getState()` returns a static snapshot of the current state at the moment of invocation. It does not re-execute when the state changes, nor does it trigger re-renders. To react to changes outside React, you must use `subscribe()` and manually handle updates.

### Can I subscribe to a specific property of the store outside React?

Yes, by applying the `subscribeWithSelector` middleware from `zustand/middleware`. This extends the store's `subscribe` method to accept a selector function as the first argument, allowing you to listen only to changes in specific properties rather than every state mutation.