Home > Blogs > Optimizely > How to Unlock Enterprise-Grade Features in Spire Using Custom Redux Store in Optimizely?
How to Unlock Enterprise-Grade Features in Spire Using Custom Redux Store in Optimizely?
Swapnil Varade
Senior Software Engineer - Optimizely
July 30, 2025
Table of Contents
In today’s fast-moving digital commerce world, businesses need more than just out-of-the-box solutions. They need the ability to tailor experiences—whether it’s custom user notifications, advanced filtering, or seamless warehouse switching. While Optimizely B2B Commerce provides a powerful framework, achieving advanced, business-specific functionality often calls for greater flexibility. That’s where building a custom Redux store in Optimizely Spire comes in.
At Royal Cyber, we help enterprises go beyond the basics—leveraging custom state management to introduce new features, streamline workflows, and scale efficiently. In this blog, we’ll break down what a Custom Redux Store in Optimizely really offers, why it matters, and how it empowers your business to innovate faster with Optimizely.
Discover Our Optimizely Solutions Today!
Why Create a Custom Redux Store in Optimizely?
Optimizely’s built-in store handles standard needs well—but what happens when your business logic outgrows those defaults?
If you’re trying to:
- Introduce warehouse switching logic,
- Track user actions with precision,
- Handle custom API calls or advanced filtering,
- Manage data unique to your business domain.
A custom Redux store gives you a clean, modular way to add these features without disrupting the core application.
By creating your own “slice” of the application state, you get full control over how your feature behaves—from managing state transitions to dispatching actions—all while preserving Optimizely’s performance and structure.
How It Works: A Simplified Overview
Here’s a high-level breakdown of how we approach building a scalable, maintainable, custom Redux Store in Optimizely Spire:
- Extend Application State: We start by expanding Optimizely’s built-in state to include your custom logic—like warehouse data or promotions—so your app knows how to manage and access it safely.
- Structure & Type Your Custom State: Defining strong, TypeScript-based interfaces ensures clean code, fewer bugs, and better collaboration across teams.
- Use Immer for Cleaner Reducers: With Immer, we write code that feels “mutable” but maintains Redux’s immutability under the hood—making logic easier to follow and manage.
- Combine Reducers for Scalability: We structure each reducer to handle a specific domain—whether it’s products, warehouses, or user preferences—so you can scale without turning your state into spaghetti.
- Register and Connect to the Main Store: Our setup integrates seamlessly with Optimizely’s core Redux store—ensuring your logic is recognized and ready to run.
- Strongly-Typed Handlers for Business Logic: Custom handlers enable clean, reusable logic for tasks like API calls, data processing, or event tracking—fully type-safe and reliable.
- Dynamic Imports for Performance: To avoid bloating your initial app load, we use dynamic imports that load only when needed—keeping performance sharp and architecture clean.
The Value for Your Business
It’s easy to get lost in the code, but here’s the bigger picture:
A custom Redux Store in Optimizely isn’t just a technical upgrade—it’s a business enabler. It allows your development team to:
- Respond faster to changing business needs
- Launch custom features with confidence
- Avoid conflicts with out-of-the-box logic
- Maintain a clean and scalable architecture
Using Immer Reducers, TypeScript, and a Scalable Setup
Primarily for developers, architects, and digital leaders looking to unlock enterprise-level customization, we walk through the steps on how to build a scalable, type-safe, custom Redux Store in Optimizely Spire using TypeScript and Immer. From setting up state and reducers to dynamically loading modules, this guide empowers developers to build robust, maintainable custom logic without interfering with core functionality.
Step 1: Extend the existing application state
Optimizely comes with a built-in ApplicationState interface for its default store.
To add your own features, you’ll need to extend this interface and include your custom state
/Data/CustomApplicationState/CustomApplicationState.ts
export default interface CustomApplicationState extends ApplicationState {
YourProject: CustomDataState;
Step 2: Define Your Custom State Structure
Decide what data your custom part will hold. For example, if you want to handle warehouse data
/Data/CustomApplicationState/CustomDataState.ts
export default interface CustomDataState {
warehouseData: WarehouseDataState;
}
Strong typing ensures that developers can safely access any piece of the state without worrying about typos or shape mismatches.
Step 3: Create a Reducer with Immer
Now, create a reducer that uses Immer to manage the state — for example, handling warehouse switching. Immer lets you write “mutating” code while keeping everything immutable under the hood.
/Reducer/YourProjectReducer/ChangeCustomerWarehouseReducer.ts
export interface WarehouseDataState {
isLoading: boolean;
Warehouse?: WarehouseModel;
}
const initialState: WarehouseDataState = {
isLoading: false,
Warehouse: undefined,
};
const ChangeCustomerWarehouseDataReducer = {
"Custom/Warehouse/BeginLoadWarehouse": (draft: Draft<WarehouseDataState>) => {
draft.isLoading = true;
},
"Custom/Warehouse/CompletedLoadWarehouse": (
draft: Draft<WarehouseDataState>,
action: { result: WarehouseModel },
) => {
draft.Warehouse = action.result;
draft.isLoading = false;
},
};
export default createTypedReducerWithImmer(initialState, ChangeCustomerWarehouseDataReducer);
Immer allows you to “mutate” state in reducers using clean syntax while still preserving Redux immutability under the hood.
Step 4: Combine Your Custom Reducers
Put all your custom reducers together in one file.
This file works as the root reducer for your custom features.
/Data/CustomApplicationState/CustomDataReducer.ts
const customDataReducerData = {
warehouseData: ChangeCustomerWarehouseReducer,
products: ProductsReducer,
promotions: PromotionReducer,
};
const customDataReducer = combineReducers(customDataReducerData as any);
export default customDataReducer;
Keeping each reducer focused on a single domain keeps your code modular and easier to maintain.
Step 5: Register your Reducer in Optimizely’s Store
To make your custom reducer work, you need to register with Optimizely’s built-in Redux store. This step connects your logic to the main application so it can start managing state.
/Reducer/CustomReducer/CustomReducer.ts
(reducers as any).YourProject= customDataReducer;
Without this registration, Optimizely won’t recognize your reducer or include it when building the store.
Step 6: Define Shared Action Types
To safely use dispatch, make sure your custom actions are included in the same type as Optimizely’s built-in actions.
This keeps everything type-safe and avoids errors.
type CustomReducers = {
YourProject: typeof customDataReducer;};
export type CustomActions = Parameters<CustomReducers[keyof CustomReducers]>[1] | AnyAction;
This allows you to dispatch any custom or default Optimizely action from handlers and middleware with proper type checking.
Step 7: Create Strongly Typed Handlers
Handlers are functions that run your business logic — like dispatching actions or calling APIs. Make sure these handlers use strong typing to catch errors early and keep your code reliable.
/Store/CustomHandlerCreator/CustomHandlerCreator.ts
type CustomDispatch = (
action: CustomActions | ((dispatch: CustomDispatch, getState: () => CustomApplicationState) => void),
) => CustomActions;
export type CustomHandlerProps<Parameter, Props> = Props & {
readonly parameter: Readonly<Parameter>;
dispatch: CustomDispatch;
getState: () => CustomApplicationState;
} & HandlerProps<Parameter, Props>;
export type CustomHandler<Parameter = {}, Props = {}> = (
props: CustomHandlerProps<Parameter, Props>
) => false | void | Promise<false | void>;
This ensures that all your business logic has full type access to custom and global state, as well as safe dispatching.
Step 8: Dynamically Import Your Store Modules
In Optimizely, you can load your custom store files only when needed by using dynamic imports. This helps keep your app modular and efficient.
To make sure your custom reducers and handlers load correctly, add the import code to your start.tsx file in the blueprint’s root folder.
/start.tsx
const store = require.context("./Store", true);
store.keys().forEach(key => store(key));
This method dynamically imports all your store files under the /Store folder. It’s particularly useful when you have many modules and want to avoid manually importing each one. This ensures scalability and cleanliness in your application. Your custom async logic is now fully integrated, type-safe, and maintainable — ideal for handling real-world business flows.
How Royal Cyber Can Help?
Building scalable, enterprise-ready customizations in Optimizely is our forte. Whether you need to integrate complex business logic, optimize performance, or ensure long-term maintainability, Royal Cyber’s experts can help you build it right the first time.
We provide:
- Custom redux store in Optimizely architecture planning
- State management best practices
- Modular, scalable reducer and handler implementation
- Seamless integration with your existing Optimizely build
Ready to implement warehouse logic, user tracking, or advanced filtering in Optimizely? Let Royal Cyber, one of the best custom solution provider for Optimizely, help you build it the right way—fast, scalable, and conflict-free. Schedule a free architecture consultation today!
Author
Poonam Chandersy
Talk To Our Experts
Recent Blogs
Agentforce and Microsoft Copilot Studio are the two dominant enterprise…
Read More »Websites used to be something you built once and basically…
Read More »Websites used to be something you built once and basically…
Read More »


