Next.js has become my default framework for web applications. Not because it's trendy, but because it solves real problems I face in every project.
The Server-First Mental Model
The App Router fundamentally changed how I think about data fetching. Instead of useEffect chains and loading states, I write async components that fetch data where they need it.
// Before: Client-side fetching
const [projects, setProjects] = useState([]);
useEffect(() => {
fetch('/api/projects').then(r => r.json()).then(setProjects);
}, []);
// After: Server component
const projects = await db.projects.findMany();The best loading state is no loading state. Server components let you eliminate entire categories of UX problems.
When I Don't Use Next.js
- **Mobile apps** — React Native with Expo is my go-to
- **Simple static sites** — Plain HTML/CSS is often enough
- **Real-time heavy apps** — Sometimes a SPA with WebSocket makes more sense
The Pragmatic Middle Ground
I don't use every Next.js feature. I skip Middleware for most projects. I avoid over-caching. I keep my route handlers simple. The goal is shipping, not framework mastery.