| name | new-store |
| description | Use this skill when the user asks to create a new Zustand store, add global state, add client state management, or create a state slice. Trigger phrases: "new store", "state management", "add state", "zustand store". |
New Zustand Store
Creates a typed Zustand store following the project's patterns.
Store Location
Stores live in the model/ folder of their slice:
src/entities/counter/model/store.ts # entity store
src/features/auth/model/store.ts # feature store
Do NOT put stores in shared/ — stores are domain-specific.
Basic Store Pattern
import { create } from "zustand";
interface SliceState {
value: string;
isLoading: boolean;
setValue: (value: string) => void;
reset: () => void;
}
const initialState = {
value: "",
isLoading: false,
};
export const useSliceStore = create<SliceState>((set) => ({
...initialState,
setValue: (value) => set({ value }),
reset: () => set(initialState),
}));
Derived State (Selectors)
Use inline selectors in components to avoid unnecessary re-renders:
const value = useSliceStore((state) => state.value);
const store = useSliceStore();
For reusable selectors, export them from the store file:
export const selectIsLoading = (state: SliceState) => state.isLoading;
const isLoading = useSliceStore(selectIsLoading);
Async Actions
import { create } from "zustand";
interface DataState {
items: Item[];
isLoading: boolean;
error: string | null;
fetchItems: () => Promise<void>;
}
export const useDataStore = create<DataState>((set) => ({
items: [],
isLoading: false,
error: null,
fetchItems: async () => {
set({ isLoading: true, error: null });
try {
const data = await api.getItems();
set({ items: data, isLoading: false });
} catch (err) {
set({ error: String(err), isLoading: false });
}
},
}));
Exporting from Slice
Always export through index.ts:
export { useSliceStore } from "./model/store";
export type { SliceState } from "./model/store";
Tests (required — write them first)
Every store ships a colocated model/store.test.ts. Write it FIRST (TDD): encode the contract as failing assertions, then implement the store to green. Assert the initial state and each action's effect on state. Reset the store in beforeEach (e.g. useSliceStore.setState(initialState)) so cases stay isolated. See the write-tests skill for patterns. npm run test:cov enforces coverage floors locally and in CI, so the store is not done until its test passes.
Checklist