Engineering
Rendering choices you
can defend in a post-mortem
Next.js offers five ways to render the same page and no opinion about which one you should pick. We choose per route, based on data freshness, cache cost and what breaks when the origin is slow, and we write the reasoning into the code.
Overview
Next.js applications where the rendering strategy is a decision, not an accident.
The App Router is capable and unforgiving. Read a cookie in the wrong place and a page you expected to be static renders on every request. Cache a fetch too eagerly and a pricing page goes stale for an afternoon. We treat caching as an architectural decision with a named owner per route, not a flag someone toggles during a launch panic.
We work in Next.js 15 and 16 with React Server Components, selecting between static generation, incremental revalidation, streaming and full dynamic rendering route by route. Cache tags are mapped to domain events, so a price change invalidates exactly the pages it touches instead of a whole segment or the entire site.
Where it runs matters as much as how it is written. We ship to Vercel when the platform primitives earn their cost, and to self-hosted Node on ECS or Kubernetes when data residency, private network access or procurement rules make that the only viable answer. Both are supported paths here, not grudging compromises.
- 0.42s
- Median time to first byte on Tinsmith Retail category pages after the ISR rework
- 88%
- Share of page views meeting all three Core Web Vitals thresholds in field data
- 14h to 9min
- Time for a catalogue change to propagate across 40,000 generated pages
Capabilities
What this covers
Six areas we staff properly. If your problem sits outside them, the honest note at the foot of this page says so.
App Router architecture
Route groups, parallel and intercepting routes, and layout boundaries arranged so a slow third-party call degrades one panel with a skeleton instead of blocking the entire page shell from streaming.
Caching and revalidation design
Per-route rendering strategy documented in code, cache tags tied to domain events, and on-demand revalidation wired to your CMS or order system so every page has a stated maximum staleness.
Server Actions and mutations
Mutations that run on the server with Zod schemas shared across both sides, progressive enhancement where the form matters, and idempotency keys on anything that moves money or stock.
Core Web Vitals and SEO
Metadata generation, structured data, canonical and hreflang handling for multi-region sites, and image and font strategy tuned until field data from real users sits inside Google's thresholds.
Self-hosted and hybrid deployment
Standalone output builds, hardened container images, incremental regeneration backed by a shared Redis cache, and the tracing you need to operate Next.js without a platform doing it for you.
Pages Router migration
Route-by-route moves with both routers live in one application, getServerSideProps rewritten into server components, and a documented rollback at every step so a bad week costs hours, not sprints.
Deliverables
What you get
- Next.js application with the rendering strategy for every route documented in code
- Cache tag map linking domain events to the exact routes they invalidate
- Core Web Vitals dashboard fed by field data from real user sessions
- Deployment configuration for Vercel or self-hosted Node, including the build pipeline
- Load test results at forecast peak traffic plus three times headroom
- Runbook covering cache flushes, failed revalidations and rollback procedure
Stack
What we build it with
- Next.js 16
- React 19
- TypeScript
- Turbopack
- Tailwind CSS
- Drizzle ORM
- PostgreSQL
- Redis
- Zod
- Playwright
- Sentry
- Vercel
Process
How the engagement runs
Two-week increments against a written definition of done. You can stop at any increment boundary and keep everything built so far.
Inventory every route
We list each route, agree in writing how stale it may be and who is accountable when it is wrong. That table drives every rendering decision that follows.
Design the cache graph
Domain events are mapped to cache tags and revalidation triggers before any page is written, which is the only reliable way to avoid whole-site purges later.
Build with instrumentation on
Routes ship with tracing, error capture and Web Vitals reporting from the first deployment, so performance regressions surface in hours rather than at launch.
Test the failure paths
Load tests at forecast peak, plus deliberate origin timeouts and cache misses, to confirm degradation is graceful and the runbook actually matches reality.
Launch and watch the field data
We stay through the first two weeks in production, tuning stale times and streaming boundaries against real traffic instead of synthetic lab scores.
When this is the wrong engagement
If your product is a data-dense internal tool behind single sign-on with no search visibility requirement and no server rendering benefit, a plain React SPA on Vite builds faster and gives your team fewer runtime concepts to hold in their heads.
FAQ
Questions we get asked
- Vercel or self-hosted?
Vercel if you want incremental regeneration, image optimisation and edge routing to work without you operating them, and you can accept the egress bill at your traffic. Self-hosted if data residency, private VPC access or procurement rules decide it. We build for either and say which we recommend in week one.
- Is the App Router ready for a large application?
It has been production-viable since Next.js 14, and the remaining sharp edges are caching semantics rather than stability. The teams that struggle are those who ported Pages Router habits unchanged. Budget time to relearn data fetching rather than time for framework bugs.
- How do you avoid the caching surprises people complain about?
By deciding freshness per route before writing code and asserting it in tests. Each route has a documented staleness budget, and integration tests check that a domain event invalidates the pages it should. Surprises come from implicit defaults, so we make every default explicit.
- Can Next.js sit in front of our existing CMS or commerce backend?
Yes, and that is the most common shape we build. Contentful, Sanity, Strapi, commercetools and bespoke APIs all work through the same pattern: typed data access, tagged caches and webhooks from the source system that trigger targeted revalidation rather than full rebuilds.
Related
More in Engineering
Engineering
Blockchain Solutions
Permissioned ledgers, tokenised assets and independently audited smart contracts.
Engineering
IoT Development
Firmware, connectivity and telemetry pipelines for devices you cannot easily reach.
Engineering
Legacy Modernisation
COBOL, Delphi, WebForms and Oracle Forms moved off, without a big-bang cutover.

