Next.js's App Router introduces a file-based convention for loading states (loading.tsx), but it suffers from fundamental design issues that create poor user experiences, especially when combined with static generation and caching strategies.
What We Experienced
The Scenario
Building a digital garden with:
Local MDX content
Static metadata from JSON files
SSG (Static Site Generation) for topic pages
generateStaticParams for pre-rendering routes
Expected Behavior
First visit to /topics/analytics - Page loads (maybe shows loader briefly)
Navigate away to /topics
Return to /topics/analytics - Instant navigation from cache, no loader
Actual Behavior
Every navigation showed the loading component (animated flower), even for:
Previously visited pages
Statically generated pages
Pages with no actual data fetching
The Root Causes
Issue 1: loading.tsx Shows on Every Navigation
Even though Next.js claims "loading states are cached and reused on navigation for instant navigation," the reality is different.
When you have loading.tsx in a route segment, Next.js creates a Suspense boundary that triggers on every navigation transition, causing visual flashes even for cached content.
Issue 2: Conflicts with generateStaticParams
GitHub Issue #77322 (Open since 2025)
loading.tsx fundamentally breaks when combined with ISR features:
1// This combination doesn't work properly
2export async function generateStaticParams() {
3 return topics.map((topic) => ({ topic }))
4}
5
6export default async function Page({ params }) {
7 // Static page, should be instant
8 return <div>Content</div>
9}
With app/topics/[topic]/loading.tsx present:
❌ Loading state may not appear at all
❌ Or appears every time despite pages being pre-rendered
Same smart behavior - only shows loading when actually loading, not on cached data.
The Irony
Vercel created SWR specifically to solve smart caching and loading states, yet Next.js's built-in loading.tsx pattern doesn't have the same intelligence.
Evidence: GitHub Issues
Issue #77322 - loading.tsx with ISR (OPEN)
Status: Unresolved since March 2025
Problem: Using generateStaticParams breaks loading.tsx
Impact: 7+ developers affected, no official fix
Quote:
"loading.tsx contents don't appear when using ISR, and removing generateStaticParams makes the loading spinner work but removes cached route benefits"
Issue #43548 - Link Navigation Not Instant
Status: Marked "Completed" but users still report issues
Problem: Loading states appear with delay, not instantly
Impact: "Navigation creates just horrible experience"
Vercel's Response:
Technical explanation that this is "how it works" - closed without architectural fix
Issue #9989 - Blank Pages on Back Button
Status: Closed (older issue)
Problem: Dynamic SSR pages show blank content when using browser back
Impact: Production deployments affected
This proves the concern about blank pages without loading.tsx is real, not theoretical.
Issue #54514 - Request to Disable Router Cache
Problem: Router cache revalidates after 30 seconds
User Request: Need ability to disable or control cache behavior
Status: Ongoing discussion
Why This Matters
For Digital Gardens / Content Sites
Pages with:
Local content
No external API calls
Static generation
Should not need complex loading state management. The content exists at build time and should load instantly.
Next.js markets itself as "batteries included," but the reality is:
Multiple caching layers (Server, Data, Router, Full Route)
File-based conventions that conflict with each other
Assumptions that don't hold in real-world conditions
"Solutions" that create new problems
The Trade-off
What you gain:
SEO-friendly SSR
Co-located API routes
Vercel deployment integration
Edge runtime capabilities
What you pay:
Complexity managing loading states
Debugging caching behavior
Working around framework limitations
Constant mental model of server/client boundaries
Is It Worth It?
For many apps, especially those that don't need aggressive SEO or server-side rendering, the complexity doesn't pay for itself.
Traditional SPAs with smart client-side caching often provide:
Better navigation UX
Simpler mental model
Fewer edge cases
More predictable behavior
Conclusion
Next.js's loading.tsx pattern represents a fundamental design gap:
File-based conventions can't adapt to runtime conditions
Conflicts with ISR/SSG remain unresolved (Issue #77322)
No smart caching like React Query or SWR
Forces binary choice: flash on every navigation OR blank on slow loads
The GitHub issues prove this isn't user error or misconfiguration - it's a known framework limitation that affects production applications.
What Next.js Should Learn From
React Query's Philosophy:
Runtime intelligence over file conventions
Stale-while-revalidate by default
Smart loading states
Granular cache control
Until Next.js addresses these gaps:
Be cautious with loading.tsx
Test navigation behavior thoroughly
Consider client-side data fetching for better UX
Don't assume "working as designed" means "good design"
Final Thought
The fact that Vercel created SWR - which solves these problems elegantly - shows they understand smart caching. The question is: when will Next.js learn from its own ecosystem?