Engineering
Overview
A deep-dive into the architecture patterns, folder structures, and performance strategies that keep large Next.js codebases maintainable as they grow.
Jordan Mercer
Next.js gives you a lot of power out of the box — but with that power comes the responsibility of structuring your app well. I've seen 20-line demos turn into 50,000-line nightmares because teams didn't plan for growth.
Folder structure visualization
After rebuilding three different Next.js apps that had grown out of control, we landed on a modular architecture that works from day one to enterprise scale.
Instead of scattering components by type, group them by feature:
src/
features/
auth/
components/
hooks/
api/
types/
dashboard/
components/
hooks/
api/
types/
shared/
ui/
lib/
types/
This keeps related code together and makes deletion — the most underrated scaling skill — trivially easy.
Data fetching patterns diagram
Never mix these layers in the same component. Create dedicated data layer components that handle one pattern exclusively.
next/image with explicit width/heightloading="lazy"Dynamic imports aren't just for routes. Split heavy components:
const HeavyChart = dynamic(() => import('./HeavyChart'), {
loading: () => <ChartSkeleton />,
ssr: false
})
For 80% of apps, Zustand + React Query is the perfect stack:
State management comparison chart
Don't put URL params in global state. Use Next.js router for those.
Wrap every major feature in an error boundary:
<ErrorBoundary fallback={<FeatureFallback />}>
<DashboardSection />
</ErrorBoundary>
When one part breaks, the rest keeps working. This isn't optional at scale.
Run unit tests on every commit. Integration tests on PRs. E2E tests before deployment.
Testing pyramid visualization
Set these up on day one:
When the app grows to 100k users, you won't be guessing what broke.
✅ Feature-based folder structure
✅ Data fetching layer separation
✅ Dynamic imports for heavy components
✅ Error boundaries at feature boundaries
✅ Monitoring on day one
✅ CI/CD with progressive testing
The projects that survive 50x growth aren't the ones with perfect code — they're the ones with deliberate architecture decisions made early. Your future team will thank you.
Written by
Jordan Mercer
Keep Reading
RSCs aren't just an optimization — they're a completely new way to think about data fetching and rendering. Here's the mental model that finally made it click.
After using Prisma on dozens of production apps, we've settled on a set of patterns for migrations, seeding, relations, and query optimization.
We turned on strict mode across a 60k-line codebase. Here's every error we hit, how we fixed them, and why we'd do it again.
Let's work together