Migrating Universal Kids From Drupal 7 to Drupal 8 Without Rebuilding the React Front End
Consolidating a Decoupled Architecture for an NBCUniversal Property
How a four-person Lullabot team migrated NBCUniversal's Universal Kids site from Drupal 7 to Drupal 8, retiring a legacy Java/MongoDB layer while preserving the React single-page application's API contract.
Executive Summary
Universal Kids is a cable television brand owned by NBCUniversal. Its web presence ran on an architecture that had grown more complicated than it needed to be: a Drupal 7 content management system paired with a legacy Java application and a MongoDB database, all feeding a decoupled React single-page application (SPA) on the front end.
That architecture wasn’t unreasonable when it was built — decoupling a front end from a CMS backend was, and still is, a legitimate pattern. But three separate systems (Drupal 7, the Java application, and MongoDB) sharing responsibility for content and data meant three separate things that could break, three separate things to patch and keep secure, and three separate mental models for anyone trying to reason about where a given piece of content actually lived.
Lullabot was brought in to migrate the CMS from Drupal 7 to Drupal 8 and, in the process, consolidate that three-system backend into a single Drupal 8 installation — while leaving the React front end that editors and viewers already depended on intact, and without breaking the API contract that front end relied on.
I worked on this project as a Senior Developer, alongside a small, named team: Andrew Berry (VP of Technology), Juampy NR (Lead Engineer), and Salvador Molina Moreno (Senior Developer). Because the public record names only four people on this engagement, I can speak somewhat more directly about the kind of work a senior developer on a team this size would be doing — while still being clear that specific architectural calls were made collaboratively, led by the project’s Lead Engineer, not unilaterally by any one contributor.
The Environment Before Migration
Before the migration, Universal Kids’ stack looked like this:
| Layer | Role before migration |
|---|---|
| Drupal 7 | Primary CMS for editorial content |
| Legacy Java application | Additional application logic, separate from Drupal |
| MongoDB | Data storage tied to the Java application |
| React SPA | Decoupled front end, consuming APIs from the backend |
That arrangement meant the “backend,” from the React application’s point of view, wasn’t really one system. It was two systems — Drupal 7 and the Java/MongoDB application — each exposing some portion of the data the front end needed, independently versioned, independently deployed, and independently at risk of drifting out of sync with each other.
Drupal 7 itself was also aging. Drupal 7’s long-term support timeline, and the broader ecosystem’s shift toward Drupal 8’s object-oriented architecture and Symfony components, made staying on Drupal 7 an increasingly expensive choice regardless of the Java/MongoDB question. Migrating to Drupal 8 wasn’t optional long-term; the only real question was whether to carry the legacy Java/MongoDB layer forward into the new architecture or use the migration as the opportunity to retire it.
Architecture Overview
The target architecture consolidated content and data responsibilities into a single Drupal 8 system, while keeping the React front end’s integration surface intact.
| Layer | Role after migration |
|---|---|
| Drupal 8 | Single system of record for content and data, replacing Drupal 7 + Java + MongoDB |
| React SPA | Unchanged front end, continuing to consume APIs — now served entirely from Drupal 8 |
| Varnish | Caching layer in front of the application |
| Docker / CircleCI / Tugboat | Containerized builds, CI automation, and disposable preview environments for the migration work itself |
The React application didn’t need to know, or care, that its data now came from one consolidated Drupal 8 system instead of two separate systems. That was the point: the migration was designed so the front end’s contract stayed stable while everything behind it changed. Engineering Approach Note The React SPA was already working and already depended on by editors and viewers. Rebuilding it alongside the backend migration would have multiplied risk and scope at the same time, for no real benefit — the front end wasn't the part of the system that was causing operational pain. Treat the migration as a backend consolidation project with a hard constraint: the React application's API contract must keep working throughout and after the migration. Drupal 8 takes over the responsibilities previously split across Drupal 7 and the Java/MongoDB layer, but it does so behind the same interface the front end already expects. Preserving an existing API contract while changing everything behind it is more constraining than a clean-slate rebuild would be — every piece of consolidated functionality has to be mapped back to what the front end already expects, rather than designed from scratch. That constraint is also exactly what kept the project's risk bounded.AN-001 — Consolidate the Backend Without Rebuilding the Front End
Context
The Approach
Tradeoffs
Preserving the React API Contract
The decoupled front end being migration-agnostic was a deliberate design goal, not an accident. In practice, this meant the team had to understand the full surface area of what the React application was actually consuming from the backend — every endpoint, every data shape — before changing what sat behind it. Engineering Approach Note A decoupled front end only stays stable if its contract with the backend stays stable. Consolidating two backend systems into one creates many opportunities to subtly change a response shape, an endpoint path, or a data type in ways the front end wasn't written to tolerate. Map the React application's existing API consumption thoroughly, and build the consolidated Drupal 8 backend to serve equivalent data through equivalent contracts, verified against the running front end rather than assumed from documentation alone. This approach trades migration speed for front-end stability. According to Lullabot's case study, the result was a reduction in React application errors post-migration — consistent with a disciplined, contract-first migration rather than a looser "migrate and fix forward" approach.AN-002 — Migrate the Backend Without Breaking the Contract the Front End Depends On
Context
The Approach
Tradeoffs
Retiring Java and MongoDB
Carrying a legacy Java application and MongoDB forward indefinitely alongside Drupal would have meant NBCUniversal continuing to maintain, patch, and operate two independent technology stacks for one property, long after the original reasons for that split had stopped mattering. The migration used the Drupal 8 rebuild as the natural opportunity to fold that functionality into Drupal and retire the legacy layer entirely. Engineering Approach Note Maintaining a separate Java application and MongoDB database alongside Drupal meant two extra systems to patch, scale, and reason about, for functionality that didn't obviously need to live outside Drupal. Fold the functionality the Java/MongoDB layer had been providing into Drupal 8 itself, using Drupal 8's broader content modeling and API capabilities (relative to Drupal 7) to absorb responsibilities that had previously required a separate application. This added scope to the migration — it was no longer a like-for-like CMS upgrade, but a consolidation project. The payoff was a single system of record going forward, with one deployment pipeline and one technology stack to operate instead of three.AN-003 — Retire the Legacy Java/MongoDB Layer Into Drupal 8
Context
The Approach
Tradeoffs
A Test-Driven, Disposable-Environment Toolchain
The project’s public listing names a specific toolchain: Docker, MySQL, CircleCI, Tugboat, Varnish, and Git, alongside project-management tooling (Jira, Smartsheet, and a “Throughput Forecaster”). That combination describes a fairly standard, solid modern Drupal delivery pipeline for its time — containerized local and CI environments, automated builds, and disposable preview environments per change, rather than a shared, hand-maintained staging server. Engineering Approach Note Migrating a content layer that three separate systems used to share, while keeping a live front end working, is hard to verify by manual inspection alone. The team needed a way to test migration logic and review changes without risking the production environment or waiting on a single shared staging server. Use Docker-based environments with CircleCI for automated builds and Tugboat for disposable, per-change preview environments, and apply test-driven development practices to the migration logic itself. Per Lullabot's case study, this combination surfaced bugs that existed in the original application — not just migration defects — because writing tests against the existing behavior exposed assumptions that had never been verified. Building out this tooling and writing tests for legacy behavior takes upfront time that a faster, less rigorous migration wouldn't spend. The case study credits this approach with the project launching faster than originally planned overall — consistent with catching integration problems early, in CI and preview environments, rather than late, in production.AN-004 — Disposable Environments and Test-Driven Migration Work
Context
The Approach
Tradeoffs
Outcomes
Per Lullabot’s public case study, the migration delivered improved site performance, reduced React application errors, a better editorial experience for the content team, and a faster-than-planned launch — with test-driven development surfacing bugs in the pre-existing application along the way.
The case study also includes a client quote:
“Lullabot was an amazing partner…we immediately noticed great improvements to the site’s speed and responsiveness.”
— Samantha Seid, Associate Content Producer, NBCUniversal
That kind of outcome — a non-technical stakeholder noticing speed and responsiveness improvements without being told to look for them — is usually a reasonable signal that a migration project met its real goal: make the system better for the people using it day to day, not just cleaner on an architecture diagram.
Working as a Four-Person Team
This was a small, named team: Andrew Berry as VP of Technology, Juampy NR as Lead Engineer, Salvador Molina Moreno as Senior Developer, and myself as Senior Developer. With only four people credited publicly, it’s fair to say the engineering decisions throughout this migration were made collaboratively among a tight group, under the Lead Engineer’s technical direction, rather than by a large committee or a single architect working in isolation.
As a Senior Developer on that team, my contribution sat within that collaborative structure — working through migration logic, content modeling, and integration details alongside Juampy and Salvador, under Andrew’s technical leadership. The public case study doesn’t attribute specific lines of work to specific individuals, and I’m not going to invent that attribution here. What I can say honestly is that a team of this size doesn’t have room for passengers — everyone on a four-person engineering team for a project like this is doing real technical work, even when the public record credits the team rather than breaking out who did what.
Lessons Learned
A few things generalize beyond this specific project.
Decoupled architectures should decouple on purpose, not by accretion. Universal Kids’ pre-migration stack — Drupal 7, a separate Java app, and MongoDB — wasn’t decoupled as a deliberate design choice so much as it had accumulated that shape over time. Consolidating it back into one system wasn’t a rejection of decoupling as a pattern; it was recognizing that this particular three-way split had stopped earning its complexity.
A stable front-end contract is a powerful constraint for a backend migration. Committing to not touching the React application’s API contract during the migration forced discipline on the backend work, and gave the team a clear, testable definition of “done” that didn’t depend on subjective judgment calls about the front end.
Test-driven migration work finds more than migration bugs. Writing tests against existing behavior, as part of a migration, tends to surface bugs that were already there — which is valuable information, even when it wasn’t the project’s primary goal.
Small teams can take on architecturally ambitious work. A four-person team consolidating three backend systems into one, on a decoupled architecture serving a national media brand, is a meaningful scope for that team size. It worked because the scope was well-bounded: migrate the backend, preserve the front end, retire the legacy layer — not an open-ended rearchitecture.
Approach Notes Summary
| Note | Topic | Nature |
|---|---|---|
| AN-001 | Consolidate the backend without rebuilding the front end | Reconstructed approach |
| AN-002 | Preserve the React API contract through migration | Reconstructed approach |
| AN-003 | Retire the legacy Java/MongoDB layer into Drupal 8 | Reconstructed approach |
| AN-004 | Disposable environments and test-driven migration work | Reconstructed approach |
These notes describe the shape of the engineering problem and the approach a senior developer on this team would reasonably have taken — not a documented internal decision log. The outcomes they’re grounded in (reduced React errors, improved performance, a faster launch, and bugs surfaced through TDD) are drawn directly from Lullabot’s public case study.
Final Thoughts
Migrations like this one rarely get remembered for the new features they ship — mostly because the goal isn’t new features, it’s making an existing system less fragile without the people who depend on it noticing any disruption. Universal Kids’ editors kept editing, its viewers kept browsing a React application that never had to be rebuilt, and three systems of record became one. That’s a quieter kind of engineering win than launching something new, but for a four-person team taking on a consolidation of this scope for an NBCUniversal property, it was the right kind of win to aim for.
Explore all Engineering Case Studies or read ECS-003: Modernizing IndieCommerce for Independent Bookstores.