MICROMARKETING Book With Tony
← Web Development

Fast Personalized Landing Pages With Vercel Fluid Compute and Next.js Cache Controls

Personalization Should Not Put the Whole Page on the Slow Path A campaign page gets expensive when one HubSpot field turns the whole thing dynamic.

Personalization Should Not Put the Whole Page on the Slow Path

A campaign page gets expensive when one HubSpot field turns the whole thing dynamic. I have seen teams spend $80,000 a month on Google Ads, then make every click wait while the server reads Salesforce, checks a Segment audience, fetches CMS copy, and renders the same hero image for the thousandth time. That is backwards. The page should arrive fast, and the personal bits should be small.

Vercel’s 2025 Fluid compute rollout and the Next.js 15.5-era cache controls give marketing teams a cleaner split. Vercel made Fluid compute the default for new projects on April 23, 2025, and its docs describe the model as reusing function instances, allowing concurrent invocations, and scaling from zero without the old one-request-per-instance tax. Next.js 15.5 shipped on August 18, 2025, with the broader App Router direction already moving toward explicit caching. The newer Cache Components model, documented by Next.js, makes that direction plain: cache the parts you can name, tag them, and keep request-time data outside cached scopes.

Strictly speaking, Next.js 15.5 itself did not make Cache Components stable. The official 15.5 release notes focus on Turbopack builds in beta, stable Node.js middleware, TypeScript improvements, next lint deprecation, and Next.js 16 warnings. But for a marketing site maintained through late 2025, the practical stack was already visible: App Router, use cache, cacheLife, cacheTag, revalidateTag, and Vercel Functions running on Fluid compute. That is enough to change how you build landing pages.

The Old Landing Page Mistake

The bad pattern is easy to spot in app/[campaign]/page.tsx. The page reads headers() to grab UTM parameters. It reads cookies() to identify a visitor. It calls HubSpot’s Contacts API or a reverse-IP service. It asks Contentful or Sanity for campaign copy. Then it renders pricing, logos, testimonials, FAQs, and the demo form in one request. One dynamic read poisons the whole route.

That hurts paid traffic first. A Google Ads click from utm_campaign=q4-cloud-security-demo does not care that your CMS headline was edited at 9:12 a.m. It cares that the first screen shows up before the tab feels broken. In a realistic B2B campaign, I would rather serve 95 percent of the page from a cached shell and spend 40 to 120 milliseconds personalizing the industry proof block than make the whole route wait on three APIs.

The same applies to organic pages. A founder landing on /compare/hubspot-vs-pipedrive from Google does not need a live CRM lookup before the H1 renders. If the visitor has a company_size=50-200 cookie from a previous visit, show a different proof point after the shell streams. Keep the comparison copy cached for a day. Tag it as campaign:crm-comparison so a webhook can revalidate it when the CMS entry changes.

What Fluid Compute Changes

Traditional serverless is awkward for personalization because request-time work is spiky and I/O-heavy. One visitor might trigger a 90 millisecond KV read. Another waits 600 milliseconds on a CRM API. A third arrives during a LinkedIn Ads burst after a newsletter mention. Old serverless pricing and cold starts made that mix feel fragile.

Fluid compute is designed for that shape of workload. Vercel’s docs say Fluid compute can handle multiple invocations within a single function instance for Node.js and Python, reuse idle resources before allocating more, and use bytecode caching on Node.js 20 and later to reduce cold start work. Vercel’s July 28, 2025 engineering post says Fluid with Active CPU pricing powered more than 45 billion weekly requests and could save customers up to 95 percent by avoiding CPU charges during idle wait time. That matters when half your function is waiting for Salesforce or a feature-flag service.

The June 25, 2025 Vercel changelog is also relevant for campaign teams. Fluid functions moved to a 300 second default duration across plans, up from 60 seconds on Hobby and 90 seconds on Pro and Enterprise. Marketing pages should not need five minutes to render. Still, longer defaults help with background tasks after form submit: enrichment, routing, Slack alerts, and syncing a lead to HubSpot without blocking the thank-you page.

Do not read that as permission to make the landing page lazy. Fluid compute makes the dynamic part less painful. It does not make uncached rendering free. The win comes from using Fluid for the narrow request-time work and using Next.js cache controls for everything with a name, a version, and a sane refresh policy.

The Page Shape I Use

For a personalized campaign page, I split the route into four zones. The shell is cached. The campaign content is cached and tagged. The personalization decision runs at request time. The form submit runs as a server action or route handler with background work where the platform allows it.

A real page might look like this: /lp/[campaignSlug] pulls copy from Sanity, pricing snippets from a local config file, testimonials from a Postgres table, and visitor context from a signed cookie plus Clearbit-style enrichment. The hero, layout, trust bar, FAQ, and base CTA are not personal. Cache them. The proof module can vary by industry, companySize, or crmStage, but those values should be coarse. Do not cache a separate page for alice@example.com. Cache for industry=manufacturing or segment=midmarket-sales.

Next.js gives you the mechanics. With Cache Components enabled through cacheComponents: true, use cache can mark a component or async function as cacheable. cacheLife('days') fits campaign copy that changes once or twice a week. cacheLife({ stale: 300, revalidate: 1800, expire: 43200 }) fits an offer block that marketing may tweak during a launch day. cacheTag('campaign', campaignSlug) lets a CMS webhook call revalidateTag after an editor publishes the 10:30 a.m. revision.

The sharp edge is request data. The Next.js docs say cached scopes cannot call request-time APIs like cookies() or headers() directly. Read those outside the cached function, turn them into serializable inputs, and pass only the coarse value you mean to cache. That one rule prevents a lot of accidental cache fragmentation.

A Concrete Build Pattern

Here is the mental model I give a founder before we touch code. The first 800 pixels should be available without a CRM round trip. The logo strip should never wait on a visitor lookup. The personalized block can stream after the shell. The form should accept the lead even if enrichment is late.

In code, that means getCampaign(slug) uses use cache, cacheLife('days'), and cacheTag('campaign:' + slug). getProofBlock(industry) also uses use cache, but the key is industry, not the user. getVisitorContext() reads cookies, UTM parameters, and maybe a Vercel Edge Config value at request time. Then the page composes cached campaign data with a small dynamic component wrapped in Suspense.

For example, a visitor from a Salesforce account list might get segment=enterprise-revops. The page can show a case study from Workato, Okta, or another named customer if your company has rights to use that logo. A visitor from utm_source=google and utm_term=hubspot onboarding agency can get HubSpot-specific copy in one paragraph. The main campaign page stays the same cached artifact.

I would test this with numbers before calling it done. On a mid-sized SaaS page, the target I use is under 200 milliseconds TTFB for the cached shell from a nearby Vercel region, under 1.8 seconds LCP on a throttled mobile profile, and under 300 milliseconds for the personalization decision when the CRM lookup hits cache. If HubSpot or Salesforce takes 900 milliseconds, show the default proof block and finish the lookup after the response. Nobody converts because your server waited politely.

Cache Invalidation for Marketing Ops

Marketing teams care about cache invalidation because launch days are messy. Someone changes the offer from

Keep reading

Continue with practical guidance from the same topic collection.