tanstack router root route 404
In the ground since Sun Nov 02 2025
Last watered inSun Nov 02 2025
Related Topics
Referece Links
The Problem
Root route (/) returns 404 in production but works perfectly on localhost. The twist? The custom 404 page appears (not CloudFront's), meaning the app loads successfully but client-side routing is broken.
Root Causes
Issue 1: Stale Route Tree in Production
TanStack Router uses a generated file src/routeTree.gen.ts that contains all route configuration. This file:
- Is generated by @tanstack/router-plugin during development
- Must be committed to git
- Was not being regenerated during CI/CD builds
The problem:
- Route tree generates during vite dev but not during vite build
- If you update routes but don't regenerate and commit the tree, production deploys with outdated routing
Evidence:
Issue 2: Incorrect File Naming Convention
The root index route was named src/routes/index.route.tsx instead of src/routes/index.tsx.
The impact:
An empty path: '' means the route won't match /, causing the router to fall through to the notFoundComponent.
The Solution
Part 1: Automate Route Generation
Install TanStack Router CLI:
Add pre-commit hook:
Benefits:
- Route tree regenerates automatically before every commit
- Updated route tree always committed with route changes
- Production always has latest routing configuration
- No manual intervention needed
Part 2: Fix File Naming
TanStack Router's conventions:
- index.tsx → Root index route with path: '/'
- index.route.tsx → Treated differently, generates path: ''
TanStack Router File Naming Conventions
Standard Route Files
| File Name | Generated Route | Path | |-----------|----------------|------| | index.tsx | Root index | / | | about.tsx | About page | /about | | posts.tsx | Posts page | /posts | | posts/index.tsx | Posts index | /posts | | posts/$id.tsx | Post detail | /posts/:id |
Layout Routes (Pathless)
| File Name | Generated Route | Path | |-----------|----------------|------| | _layout.tsx | Layout wrapper | No path (wraps children) | | _auth.tsx | Auth layout | No path (wraps children) |
Special Suffixes
| Suffix | Purpose | Note | |--------|---------|------| | .lazy.tsx | Code-split route | Lazy-loaded on access | | .route.tsx | Alternative syntax | ⚠️ Avoid for index routes |
🎓 Key Learnings
Build-Time Route Generation
Unlike routers that discover routes at runtime, TanStack Router:
- Scans src/routes/ during development
- Generates static routeTree.gen.ts file
- This file must be committed
- Production uses committed file, not live generation
Critical implication: Update routes without committing the tree = broken production.
Development vs Production Behavior
Development:
- Vite plugin watches file changes
- Route tree regenerates automatically
- Hot module replacement works
- Everything feels "magic" ✨
Production:
- Uses committed route tree file
- No live generation
- Stale route tree = broken routes
- No HMR to mask issues
Best practice: Always test production builds locally:
Debugging Client-Side Routing Issues
Signs it's routing (not server/CDN):
- ✅ App loads (you see your UI)
- ✅ Network tab shows successful requests (200/304)
- ✅ You see custom 404 page (not server's 404)
- ❌ beforeLoad hooks don't run
- ❌ Console logs in route files don't appear
Debug steps:
- Check route tree commit history: git log src/routeTree.gen.ts
- Inspect route tree content for path values
- Verify file naming follows conventions
- Test production build locally: yarn build && yarn preview
- Compare deployed bundle with local build
Prevention Strategy
Automated Pre-Commit Hook
CI/CD Validation (Recommended)
Ideal Development Workflow
- Create/modify route files in src/routes/
- Pre-commit hook runs automatically:
- Generates route tree
- Stages routeTree.gen.ts
- Runs linting
- Commit includes both route files and route tree
- CI/CD builds with up-to-date configuration
- Production works! ✅
Summary
Problem: Root route 404 in production
Cause 1: Stale route tree file in git
Cause 2: Wrong file naming (index.route.tsx vs index.tsx)
Solution 1: Auto-generate routes on pre-commit
Solution 2: Rename to index.tsx
Result: Routes work in production
Debug Time: ~2 hours
Fix Time: 5 minutes
Lesson: File naming conventions and build-time generation are critical!