This repository is (and always was) an experimental side project, and no tickets regarding this series of articles or code will be accepted by Pega GCS.
Sweet Life ( GitHub - kamiljaneczek/Sweet-Life-Pega ) is a demo application built on top of the Pega Constellation React SDK. Instead of using Pega’s default Constellation UI components, it replaces them entirely with a custom design system built on Tailwind CSS, Base UI primitives, and Lucide icons. The app connects to a Pega Infinity 25 backend for case management, mashup UI rendering, and business logic — but the frontend looks and feels nothing like out-of-the-box Pega.
The motivation for the upgrade was threefold:
-
Support for Pega Infinity 25.2, access to React 18 features (concurrent rendering, automatic batching,
createRoot) -
Modernizing the tooling stack — ESLint 9 flat config, Storybook 8, TypeScript 5, and React Router v7 — as a consequence of upgrading to Pega SDK 25
-
Experimental changes added on top of the upgrade: Vite, Tailwind CSS v4 with Base UI, Biome instead of ESLint, and TanStack Router instead of React Router. Those changes are not directly needed when upgrading to Pega 25, those are experimental upgrades to verify if React SDKs can be used with different toolings a libraries.
As of this migration, the repository differs from the template repository that ships with the SDK sample application. This is meant to showcase one possible route, not to provide guidance on best practices.
The Migration Strategy
AI-Assisted Planning
Rather than winging it, I used Claude Code to analyze the diff between the upstream SDK 23.1 and 25.1 branches, then generate a structured migration plan. The result was a 42-task plan organized into logical phases:
-
Preparation — Create the migration branch, tag the pre-upgrade state
-
Upstream Merge — Merge the SDK 25.1.10 upstream changes with conflict resolution
-
Dependency Updates — Upgrade React, React Router, TypeScript, ESLint, Storybook
-
Component Migration — Systematically replace Material-UI with Tailwind/Base UI across 78+ override components
-
Build & Tooling — Replace Webpack with Vite, migrate Tailwind to v4, update tsconfig, Storybook config, auth hooks
-
Verification — Lint, build, test, fix remaining issues
Branch Strategy
I worked on a dedicated sdk-upgrade-25.1.10 branch off main. The first step was merging the upstream Pega SDK changes, resolving conflicts, and then layering our custom changes on top. This preserved the ability to compare against both the old and new SDK baselines.
The repository maintains three long-lived branches to reflect different stages of the project’s evolution:
-
pega23-branch— The original Pega Constellation SDK 23.1 codebase, preserved as a reference point -
react-router-branch— The SDK 25.1 upgrade with React Router v7, representing the intermediate migration state -
main— The current active branch, fully migrated to SDK 25.1 with TanStack Router replacing React Router for file-based routing and tighter integration with TanStack Query
What Changed: The Big Picture
React 17 to 18
The entry point switched from the legacy ReactDOM.render() to the new createRoot API. The Constellation mashup initialization in src/lib/constellation.tsx required a MutationObserver fallback for embedded mode, where the target DOM element might not exist when rendering is triggered. We also removed MUI’s ThemeProvider and CssBaseline wrappers from the root component.
React Router v5 to v7
A clean migration: Switch became Routes, component={Home} became element={<Home />}, imports moved from react-router-dom to react-router, and duplicate .html routes were removed. The exact prop was dropped since v7 matches exactly by default.
ESLint 9 Flat Config
The traditional .eslintrc.json was replaced with eslint.config.mjs using the new flat config format — plugins imported as ES modules, globals replacing the old env property, and the PCore global declared as 'readonly'.
After migrating to Pega 25, I fully replaced ESLint with Biome, which is faster and easier to set up.
Storybook 7 to 8
Config migrated from JavaScript to TypeScript. The preview file was updated to use the new Preview type, deprecated addons like @storybook/addon-knobs were removed, and theme detection now reads from sdk-config.json.
TypeScript 5
TypeScript jumped from 4.9 to 5.9, requiring skipLibCheck: true (necessary due to conflicting type definitions in Pega packages), resolveJsonModule: true, and moduleResolution: "Bundler" for Vite compatibility.
These changes were core to the 23-to-25 upgrade and have been followed by my custom changes.
Experimental changes
Webpack to Vite
The entire build toolchain was replaced. Webpack’s complex webpack.config.js — with its loader chains, plugin setup, CleanWebpackPlugin, url-loader, file-loader, and manual PostCSS configuration — was replaced by a single vite.config.ts. Vite’s native ESM-based dev server provides instant HMR instead of Webpack’s slow rebuild cycles. Storybook still uses @storybook/react-webpack5 internally, but the main app build is fully decoupled from Webpack.
Tailwind CSS v3 to v4
Tailwind v4 represents the most significant architectural change in Tailwind’s history — moving from JavaScript configuration to CSS-first configuration. The tailwind.config.js file was deleted entirely. All theme configuration now lives in src/app.css using the new @theme directive, with @import "tailwindcss" replacing the old @tailwind directives.
ShadCN/Radix UI to Base UI
The design system primitives were migrated from ShadCN components (built on Radix UI) to Base UI (@base-ui-react v1.2.0) — the unstyled component library from the MUI team, designed specifically for custom design systems. All @radix-ui/* packages were removed from the dependency tree.
How Claude Code Helped
I was lucky enough to have a document listing best practices around the SDK upgrade, prepared by others prior to my migration. Based on this documentation, I asked Claude Code to prepare a detailed migration plan.
What worked well:
-
Migration plan generation — Analyzing the diff between SDK versions and generating the 42-task plan saved hours of manual analysis
-
Repetitive component migration — The MUI-to-Tailwind/Base UI conversion followed a predictable pattern across 78+ components. Where a human would cut corners by component 30, the AI maintained consistent quality throughout
-
Conflict resolution — Intelligently resolving merge conflicts while preserving custom Tailwind modifications and adopting new SDK patterns
-
Build tooling overhaul — Handling the Webpack-to-Vite migration, Tailwind v3-to-v4 config rewrite, and Storybook/ESLint config changes holistically
What needed human oversight:
-
Pega runtime behavior — Manual testing against an actual Pega Infinity server was essential
-
Design decisions — Choosing dark mode approaches, icon selections, and component styling
-
TypeScript error triage — Deciding which errors to suppress vs. fix required domain expertise