NEXSUM_LABS
  1. Home
  2. Work
  3. A hiring-platform SaaS rebuilt its marketing surface and moved p75 LCP from 4.8s to 2.1s
Book a call

[ Case study ]

HR technologyNext.js (App Router)React Server ComponentsHeadless CMSVercel

A hiring-platform SaaS rebuilt its marketing surface and moved p75 LCP from 4.8s to 2.1s

The marketing site — pricing, feature pages, the blog — sat on a legacy templated stack where every page shipped a large JavaScript bundle regardless of content. Field data showed p75 LCP at 4.8s on mobile, and paid acquisition was landing on pages that scored poorly on the exact metrics Google reports publicly.

CLIENT a hiring-platform SaaS company — FOCUS Decide the rendering model per route

Next.js DevelopmentWeb DevelopmentNext.js DevelopmentHR technologyRepresentative example
Client
a hiring-platform SaaS company
Industry
HR technology
Engagement
10 weeks — systems pod — 2 engineers
Service
Web Development / Next.js Development
Headline outcome
p75 LCP on mobile marketing pages, 28-day CrUX window after full rollout: 4.8s → 2.1s, read from CrUX field data

Representative examplesEvery case study in this library is an illustrative composite of the kind of engagement we deliver — written to show our method and standards, not to name clients.

Where they started

Their product helps mid-market recruiters run hiring, and the marketing surface — pricing, feature pages, a high-cadence blog — does heavy paid-acquisition work. Two people run that site part-time while holding other roles. Content lives in a headless CMS the editorial team likes; the template stack in front of it dates from an earlier era and ships the same JavaScript bundle to a pricing page and a blog post alike.

What it was costing

The marketing site — pricing, feature pages, the blog — sat on a legacy templated stack where every page shipped a large JavaScript bundle regardless of content. Field data showed p75 LCP at 4.8s on mobile, and paid acquisition was landing on pages that scored poorly on the exact metrics Google reports publicly.

What they could see

  • On mid-range phones, pages took close to five seconds to become readable, and paid clicks bounced before the headline settled.
  • A pricing page and a blog post downloaded the same large JavaScript bundle.
  • Bounce on the highest-traffic landing pages climbed whenever paid spend ramped up.
  • The two part-time operators refused to deploy on Fridays; a rollback had once eaten a weekend.
  • Content-only design tweaks still needed a developer, because template and logic were interleaved.

The constraints we worked inside

  • The product app was off-limits; only the marketing surface could change.
  • Two people ran the site part-time; the new stack had to be boring to operate.
  • An existing headless CMS held all content and had to stay the source of truth.

What had been tried before

They bought a performance audit and applied the quick wins: image compression, script deferral, caching headers.
The wins landed in single-digit improvement; the bundle architecture — every page shipping every component — set a ceiling that optimization couldn't move.
A CDN image-transform add-on was bolted in front of the site.
Assets got faster but the LCP element was still rendered late by the bundle, so the field numbers barely moved.

What we proposed

We proposed a rebuild on Next.js with the rendering model decided per route: content pages render on the server with request caching and ship almost no client JavaScript, while genuinely interactive pieces become small client-side islands. The image and font pipeline gets rebuilt first, because it moves the metric more than any design change. A written performance budget gates every merge in CI, so a regression is a failed check rather than a quarterly surprise. The product app stays untouched; the CMS stays the source of truth.

Just as important is what we ruled out, and why:

  • Static export of the whole marketing surfaceEditorial publishes continuously and pricing changes weekly; prebuilds would have traded one bottleneck for another and broken CMS preview.
  • Another platform migration (different host or framework)Field data blamed the payload, not the infrastructure; moving the bundle elsewhere would have carried the problem along.
  • Optimizing the legacy templated stack in placeThe quick-win round had already been done and hit the architectural ceiling; the bundle-per-page model can't be patched into per-route rendering.

How the work ran

01Decide the rendering model per route

Marketing pages moved to server components with request caching; interactive islands stayed client-side by exception — the bundle stopped shipping for content-only routes.

02Fix the asset path first

The image and font pipeline (next/image, subsetting, priority hints) was rebuilt before layout work, because it moved LCP more than any design change.

03Gate the budget in CI

Lighthouse runs against a written budget on every merge, so a regression is a failed check rather than a quarterly surprise.

Delivered by the systems pod — 2 engineers over 10 weeks, with working increments reviewed with the client every week.

The stack, and the reasoning

Next.js (App Router)
Per-route rendering for a marketing surface is the boring-to-operate choice two part-time operators asked for; an SPA framework would have shipped the same bundle problem forward.
React Server Components
Content-only routes stopped shipping client JavaScript entirely; interactivity became an exception to justify, which is the correct default for a pricing page.
Headless CMS
Editorial already works there and preview matters; keeping it as source of truth meant zero retraining and no content migration risk.
Vercel
Preview deployments per pull request gave the two operators review power without owning build infrastructure — ops time they don't have.
GitHub Actions
The Lighthouse budget runs on every merge; a regression fails a check instead of surfacing in a quarterly field-data review.

What went wrong

Obstacle

Lab scores passed from week two, but real-device field data still showed slow interactions in week six — mid-range Android behavior the lab simply couldn't reproduce.

Handled: We added field Web Vitals monitoring, traced the lag to hydration cost on the pricing table, and split it into a small island; the gap closed.

Obstacle

The headless CMS's cache-invalidation webhooks fired unreliably, so edited pricing pages occasionally served stale numbers after a publish everyone believed had cleared them.

Handled: We added a scheduled revalidation fallback and an editorial clear-cache action, and wired invalidation failures into the operators' channel so silence meant success.

How we worked together

Cadence
Monday planning, Thursday demo on a preview deployment, written metrics summary every Friday against the performance budget — the numbers came from CI and field data, not opinion.
Client side
Two part-time site operators joined every demo; the growth lead set priorities; a product engineer consulted on the CMS webhooks and analytics events.
Decisions
Rendering decisions per route were proposed in writing and approved in the Thursday demo; anything touching the product app boundary went to their CTO.
They provided
Repository access, the CMS workspace, historical field data from their analytics, and design files; the operators reserved two hours weekly for pair handover.

What changed

The headline: p75 lcp on mobile marketing pages, 28-day crux window after full rollout4.8s → 2.1s, read from CrUX field data. A second check: bounce rate on the five highest-traffic landing pages at −22%.

The two operators stopped treating deploys as events. A merge either passes the budget check or it doesn't, and the weekly metrics email gets skimmed rather than feared. Marketing runs pricing experiments without asking whether the page will survive them. The team's standing joke — don't touch the marketing site before a launch — died somewhere in the second month, and nobody has tried to revive it.

The result was read from CrUX field data against the pre-engagement baseline over the stated window, with a guardrail check on bounce rate on the five highest-traffic landing pages. Where platform-reported numbers and business outcomes differ, this record says which layer it is quoting.

What they own now

  • The Next.js repository, CI included, with the performance budget file commented for future edits.
  • Preview deployment workflow and the two operators' accounts provisioned.
  • The field vitals dashboard with alert thresholds the team agreed in writing.
  • A per-route rendering map explaining what is server, island, and cached, and why.
  • Runbooks for CMS webhook failures, including the manual revalidation fallback.

What we would do differently

We would have instrumented INP from week one — the lab passes looked clean while real-device interaction lag persisted until week six.

Web DevelopmentNext.js DevelopmentHR technologyNext.js (App Router)

Next case study

A SaaS analytics vendor rebuilt its docs and marketing surface for interaction speed