Multi-tenant apps with Next.js
How Stefan and I built a multi-tenant publishing platform serving multiple B2B media brands from a single Next.js deployment. The architecture, the middleware rewrite, and how each brand keeps its own identity.

I built my first website in 1998. Since then I've worked across the full arc of web development: table layouts, Flash, PHP, the mobile web and jQuery, Node.js, JAMStack, React, and now Next.js since 2018.
Somewhere in between I studied Media Economics and Marketing, which turned out to shape how I think about code more than any programming book. It gave me a bias: I understand that code has to serve business goals. A technical improvement might change how users behave and hence increases the conversion rate. If the team can ship faster, it's a win for the whole company.
Today I specialize in Next.js performance and architecture. Most of my work is with scale-ups where the same pattern keeps showing up: smart developers, good intentions, but they're fighting their own infrastructure. Deploys that take 20 minutes, self-managed Kubernetes that blocks modern workflows, caching strategies that nobody on the team fully understands.
Slow developer experience kills momentum.
That's the problem I work on.
How Stefan and I built a multi-tenant publishing platform serving multiple B2B media brands from a single Next.js deployment. The architecture, the middleware rewrite, and how each brand keeps its own identity.
A practical guide to running Puppeteer in a Next.js Route Handler on Vercel to render PDFs. How to work around the 250MB function bundle limit, cache the Chromium executable, and prevent concurrent downloads on cold starts.
A quick reference for the dynamic APIs and patterns that force a Next.js route into dynamic rendering. cookies, headers, searchParams, connection, fetch with no-store, and missing generateStaticParams.
Part 4 of the series: A practical guide to migrating from the previous Next.js caching model to Cache Components. What changes, what breaks, and how Date.now() cost us several days on a real project.
Part 3 of the series: The difference between revalidateTag, updateTag, and revalidatePath in Next.js Cache Components. When to use which, how to design cache tags, and how to integrate CMS webhooks for on-demand revalidation.
Part 2 of the series: Where to place the "use cache" directive in your Next.js application: on data functions, on components, or not at all. How data-level caching, UI-level caching, and Suspense streaming work together in Partial Prerendering.
Part 1 of the series: How Next.js caching evolved from path-based ISR revalidation to explicit, opt-in Cache Components. The three cache directives, Partial Prerendering, and why caching in Next.js is no longer implicit.
Why "use cache", "use workflow", and "use step" are the right approach to infrastructure boundaries in JavaScript. The case for directives over wrapper functions, and why different infrastructure should mean different syntax.
Next.js has built-in support for reporting Core Web Vitals from real user sessions. How to set up the useReportWebVitals hook and send metrics to your analytics endpoint or Google Analytics.
How a Black Friday flash sale handled 3.2 million requests at 900/sec with a 0% error rate for $18 on Vercel. Why self-managed Kubernetes costs more than the invoice shows, and what actually absorbed the traffic.
How next/image handles format conversion, responsive sizing, lazy loading, and preloading. Why the sizes prop matters more than most teams think, and how browser primitives have changed image optimization.
What seven years of building enterprise e-commerce storefronts with Next.js taught me about static generation, caching, images, and the patterns that actually matter for performance and revenue.
Core Web Vitals measure real-world user experience: loading speed, interactivity, and visual stability. What each metric means, what the thresholds are, and why TTFB matters too.