M&S Goes Headless: A Next.js KIBO Commerce Epic Across 5 Regions

"We need to rebuild M&S from scratch. Headless. Five regions. Same codebase. Oh, and it needs to support both English and Chinese. By next quarter."

That's how my current adventure at Al-Futtaim began. Because apparently, I enjoy living dangerously.

Welcome to the wild world of headless commerce, where "M&S" stands for "Marks & Spencer" but also "Madness & Suffering" depending on which day you ask me.

Chapter 1: The Headless Awakening

First things first: What is headless commerce? Imagine if you separated a mannequin's head from its body, but somehow both parts still needed to work together to sell clothes. That's headless commerce, but with more APIs and fewer plastic limbs.

"Going headless will solve all our problems! The frontend and backend can scale independently! It's the future!"
Architect who clearly never debugged API calls across 5 time zones

Spoiler alert: It didn't solve all our problems. It created new, more creative problems.

Chapter 2: KIBO Commerce - The Chosen One

Enter KIBO Commerce, our headless backend of choice. KIBO is like that sophisticated British friend who speaks eloquently but sometimes says things that make no sense whatsoever.

// KIBO API Response
{
  "success": true,
  "message": "Product retrieved successfully",
  "data": {
    "product": null,
    "errors": ["Product not found"],
    "warnings": ["This should probably be an error"]
  }
}

Me: "So... is this successful or not?"
KIBO: "Yes."
Me: "But there's an error..."
KIBO: "Successfully returned an error!"

British logic at its finest.

Chapter 3: The Multi-Region Circus

Building for one region is challenging. Building for five regions is like juggling flaming swords while riding a unicycle. In different time zones. With different currencies. And different ideas about what "urgent" means.

The Regions:

  • Australia (AU): "No worries, mate! Ship it when it's ready!"
  • Hong Kong (HK): "Must be perfect. Test everything twice."
  • Malaysia (MY): "Can it work during monsoon season with slow internet?"
  • New Zealand (NZ): "We exist too! Don't forget us!"
  • Singapore (SG): "Launch yesterday. Performance better be sub-100ms."

Chapter 4: Storybook - The Design System Hero

Our design system started with Storybook - basically IKEA instructions for UI components, but for developers. Each component was lovingly crafted from atomic design principles:

// Our component hierarchy looked like this:
Atoms (Button, Input, Text)
  ↓
Molecules (SearchBox, ProductCard, AddToCart)
  ↓
Organisms (Header, ProductGrid, CheckoutForm)
  ↓
Templates (Homepage, ProductPage, CheckoutPage)
  ↓
Pages (The final assembled madness)

It was beautiful in theory. In practice, it looked like this:

// Reality
Atoms: Perfect 
Molecules: Pretty good  
Organisms: Getting complex 
Templates: Why is everything breaking? 
Pages: *Everything is on fire* 

Chapter 5: The Great Integration Saga

We needed to integrate with more third-party services than a dating app integrates with social media:

Algolia - For search that actually works
Bloomreach - For personalization that sometimes works
Google Analytics - For tracking everything
Azure - For hosting our digital dreams
Gigya - For JWT authentication nightmares

// My component looked like this:
const ProductPage = () => {
  const [kiboData, setKiboData] = useState(null);
  const [algoliaResults, setAlgoliaResults] = useState([]);
  const [bloomreachRecs, setBloomreachRecs] = useState([]);
  const [userFromGigya, setUserFromGigya] = useState(null);
  const [myMentalHealth, setMyMentalHealth] = useState('declining');
  
  // 47 useEffect hooks later...
}

Chapter 6: The State Management Nightmare

With 5 regions, 2 languages, multiple currencies, and countless third-party integrations, our Redux store became more complex than the plot of Inception.

// Our Redux state tree
{
  auth: { user, tokens, permissions, existentialCrisis },
  cart: { items, totals, taxes, abandonedHopes },
  products: { catalog, filters, search, whyIsThisEmpty },
  ui: { modals, loaders, errors, tears },
  regions: {
    AU: { currency: 'AUD', locale: 'en-AU', status: 'working' },
    HK: { currency: 'HKD', locale: 'en-HK', status: 'mysterious' },
    MY: { currency: 'MYR', locale: 'en-MY', status: 'laggy' },
    NZ: { currency: 'NZD', locale: 'en-NZ', status: 'forgotten' },
    SG: { currency: 'SGD', locale: 'en-SG', status: 'perfectionist' }
  }
}

Chapter 7: The i18n Chinese Character Challenge

Adding Chinese language support to an English e-commerce site is like trying to fit a square peg into a round hole, except the peg is traditional Chinese characters and the hole is your CSS layout.

/* CSS that broke my soul */
.product-title {
  font-family: 'Arial', sans-serif; /* English */
}

.product-title[lang="zh"] {
  font-family: 'Microsoft YaHei', sans-serif; /* Chinese */
  line-height: 1.8; /* More spacing needed */
  word-break: break-all; /* Please don't overflow */
  /* Pray to the CSS gods */
}

Fun fact: Chinese characters don't care about your responsive design. They'll overflow your carefully crafted mobile layout and there's nothing you can do about it except cry in CSS.

Chapter 8: SSR/SSG - The Performance Dance

Next.js promised us the best of both worlds with Server-Side Rendering (SSR) and Static Site Generation (SSG). What they didn't mention was that we'd spend weeks debugging hydration mismatches.

// The dreaded hydration error
Warning: Text content did not match. 
Server: "Loading..."
Client: "Error: Cannot read property 'price' of undefined"

// My debugging process:
1. Check if it's a KIBO API issue ✓ (it usually is)
2. Check if it's a timezone issue ✓ (it sometimes is) 
3. Check if it's a regional config issue ✓ (it always is)
4. Blame the cache ✓ (when in doubt)
5. Clear everything and pray ✓ (ultimate solution)

Chapter 9: The Azure Deployment Odyssey

Deploying to Microsoft Azure across 5 regions taught me that "The Cloud" is just someone else's computer that occasionally has bad days. Usually on Friday afternoons. During important demos.

// Our Azure deployment pipeline
Build successful
Tests passing  
Deploy to staging - success
Deploy to AU - timeout
Deploy to HK - network error
Deploy to MY - success (somehow)
Deploy to NZ - forgot they exist again
⚠  Deploy to SG - works but complains about performance

The best part? Each region has slightly different Azure configurations because they were set up by different teams at different times. It's like playing Azure roulette.

Chapter 10: The JWT Token Juggling Act

Implementing dual JWT tokens (guest and authenticated) with AES-256 encryption across 5 regions was like performing brain surgery while solving a Rubik's cube blindfolded.

// The token dance
const handleAuth = async () => {
  if (isGuest && needsUpgrade) {
    const guestToken = encryptGuestToken(cartData);
    const userToken = await gigya.login(credentials);
    const mergedData = await kibo.mergeGuestAndUser(
      guestToken, 
      userToken, 
      currentRegion,
      moonPhase // probably needed for some edge case
    );
    
    // Update 17 different state management systems
    dispatch(updateEverything(mergedData));
    localStorage.setItem('tokens', JSON.stringify(tokens));
    sessionStorage.setItem('backup', JSON.stringify(tokens));
    cookies.set('fallback', encryptedTokens);
    
    // Sacrifice to the auth gods
    console.log(' Please work');
  }
}

Chapter 11: The Performance Perfectionist Singapore

Singapore had one non-negotiable requirement: everything must be FAST. Sub-100ms response times. Perfect Lighthouse scores. Instant everything.

My performance optimization journey:

  1. Image Optimization: Next.js Image component with WebP
  2. Code Splitting: Dynamic imports for everything
  3. CDN: Azure CDN with aggressive caching
  4. Bundle Analysis: Removed that one library that was 200KB
  5. Critical CSS: Inline the important stuff
  6. Service Workers: Cache everything possible
  7. Prayer: The most important optimization
// After optimization
Lighthouse Performance Score:
AU: 85 🟡 (Good enough, mate!)
HK: 92 🟢 (Excellent!)  
MY: 78 🟡 (Works on slow connections!)
NZ: 88 🟢 (We remember you exist!)
SG: 98 🟢 (PERFECTIONIST SATISFIED)

Chapter 12: The Custom Hooks Revolution

By the end of the project, I had more custom hooks than a fishing tackle shop:

// My custom hooks collection
useAuth() // For authentication chaos
useCart() // For shopping cart madness  
useKiboApi() // For API call suffering
useRegionConfig() // For multi-region pain
useAlgoliaSearch() // For search functionality
useBloomreach() // For personalization attempts
usePWAInstall() // For mobile app feelings
useI18n() // For Chinese character battles
usePerformance() // For Singapore's demands
useErrorBoundary() // For when everything breaks
useCoffeeLevel() // For survival tracking

The Unexpected Victory

Despite everything - the API inconsistencies, the multi-region complexity, the Chinese characters that broke layouts, the Azure deployments that failed on Fridays - it worked. Not just worked, but worked beautifully.

The Results:

  • Performance: All regions under 2s load time
  • Mobile-first: 78% mobile traffic, optimized experience
  • Multi-region: Seamless experience across 5 markets
  • Personalization: Bloomreach delivering relevant content
  • Search: Algolia making product discovery magical
  • Conversion: Cart abandonment reduced by 34%
  • Coffee consumed: Approximately 847 cups

Lessons Learned

  1. Headless doesn't mean brainless - Plan your architecture carefully
  2. Multi-region is multi-complex - Each region has its own personality
  3. Third-party integrations multiply complexity exponentially - Choose wisely
  4. Chinese characters will break your layout - Plan for it
  5. Performance is a feature, not an afterthought - Singapore taught me this
  6. Custom hooks are your friends - Embrace them
  7. Azure has moods - Plan your deployments accordingly

The Epic Conclusion

Building a headless e-commerce platform for M&S across 5 regions with Next.js and KIBO Commerce was like directing a multilingual orchestra while skydiving. Terrifying, exhilarating, and somehow beautiful when it all comes together.

"In the end, we didn't just build an e-commerce platform. We built a testament to human stubbornness and the power of really good coffee."
Me, reflecting on the journey

Would I do it again? Ask me after I've recovered. And had more coffee. Maybe in 2026.

To my fellow developers venturing into headless commerce: May your APIs be consistent, your deployments be successful, and your coffee be strong. You're going to need all three.

P.S. - The platform is live, serving millions of customers across 5 regions, and somehow still working. That's either a testament to solid architecture or the universe's sense of humor. I choose to believe it's both.