Frontend modernization dashboard

Frontend Modernization

Led the biggest code modernization effort since 2019, upgrading from Node 14 to Node 22 and React 16 to React 18 while coordinating security, API compatibility, and CI/CD migration.

React 18 Node.js 22 GitHub Actions Apollo Client v3 Project Lead

The Challenge

Our codebase was running on Node 14 (EOL) and React 16, creating security vulnerabilities and blocking access to modern tooling and performance improvements.

Legacy Runtime & Framework

Node 14.20.1 reached end-of-life with React 16.14.0, creating security risks and compatibility issues

Security Vulnerabilities

Outdated dependencies (Axios, Sentry) exposed known security vulnerabilities in production

Technical Debt Accumulation

Legacy patterns (Enzyme, Apollo v2, deprecated React APIs) blocked modernization and created maintenance burden

The Solution

I led a comprehensive, phased modernization spanning 2H 2025, coordinating with backend and infrastructure engineers to ensure zero downtime and maintain API compatibility.

Core Runtime Upgrade

Migrated Node 14 → 22 LTS and React 16 → 18 with Docker image updates and CI/CD pipeline migration from Bitbucket to GitHub Actions

Security-First Dependency Updates

Systematically upgraded critical dependencies (Apollo Client v3, Axios, Sentry) and eliminated 40+ security vulnerabilities

Modern Testing & Tooling

Replaced Enzyme with React Testing Library, upgraded to modern testing patterns aligned with React 18's concurrent features

My Role

As the main project owner across 2H 2025, I coordinated cross-functional efforts, made architectural decisions, and ensured smooth delivery through systematic planning and execution.

Project Leadership & Coordination

  • Partnered with 1 backend and 1 infrastructure engineer to ensure API compatibility and deployment security throughout the migration
  • Defined migration scope and phases, balancing quick wins with high-complexity upgrades to deliver value incrementally
  • Established testing and rollback procedures to maintain zero production incidents during the modernization

Technical Implementation

  • Executed Node 14 → 22 and React 16 → 18 upgrades, resolving breaking changes in concurrent rendering and lifecycle methods
  • Migrated Apollo Client v2 → v3, refactoring GraphQL layer across entire application with backwards-compatible API design
  • Converted Enzyme test suites to React Testing Library, establishing behavior-first testing patterns for the team
  • Replaced deprecated React APIs (react-visibility-sensor → Intersection Observer, react-loadable → React.lazy/Suspense)

Implementation Strategy

A phased approach prioritizing critical security updates first, followed by systematic modernization of testing frameworks and deprecated APIs.

Tech Stack

  • Node.js 22 LTS – upgraded from 14.20.1 with Docker and CI/CD pipeline updates
  • React 18.3.1 – migrated from 16.14.0 with concurrent rendering support
  • Apollo Client v3 – complete GraphQL layer rewrite from v2
  • GitHub Actions – migrated CI/CD from Bitbucket Pipelines
  • React Testing Library – replaced Enzyme with behavior-first testing

Strategic Decisions

  • Prioritized security dependencies (Axios, Sentry) before nice-to-have modernizations (ESLint, Prettier)
  • Completed ahead of schedule, allowing expansion of scope to include React Router v6 and Stripe Elements updates
  • Deferred code quality tooling (ESLint major versions) and UI library updates to future iterations

The Impact

Successfully delivered the largest modernization effort in company history, ahead of schedule.

40+
Security vulnerabilities fixed
Ahead
Of schedule delivery
Modern
CI/CD infrastructure

Looking Back

Reflections on the development process and improvements for future projects.

Phased Delivery Creates Value Early

Breaking modernization into phases (core runtime → security → nice-to-haves) allowed us to ship security fixes quickly while building towards comprehensive modernization.

Test for Breaking Behavioral Changes

Apollo Client v3 enforces object immutability through Object.freeze(), causing 2 production incidents where our code mutated cached objects. Integration tests would have caught this before deployment.

Comprehensive Testing Enables Confidence

Investing in testing framework migration alongside runtime upgrades gave us confidence to move fast without breaking production.

Back to All Projects

Explore more case studies and technical projects