Next.js 13+ introduced the App Router, a new paradigm for building React applications. As CTO of Softechinfra, I've migrated multiple production apps. Migration requires careful planning. Here's how to do it right.
Understanding the Changes
Pages Router vs App Router
- Pages Router:
- File-based routing in /pages
- getStaticProps, getServerSideProps
- Client-side by default
- Familiar patterns
- App Router:
- File-based routing in /app
- Server Components by default
- async/await in components
- New data fetching patterns
Key Differences
- Routing:
- page.tsx instead of index.tsx
- layout.tsx for shared layouts
- loading.tsx for suspense
- error.tsx for error boundaries
- Data Fetching:
- fetch() with caching
- No getStaticProps/getServerSideProps
- Server Components for data
- Streaming and Suspense
Migration Strategy
1. Incremental Adoption
- Don't rewrite everything:
- Both routers work together
- Migrate page by page
- Test thoroughly
- Roll back if needed
2. Start Simple
- Begin with:
- Static pages
- Simple components
- Low-risk areas
- Well-tested functionality
3. Pattern Translation
Data fetching:
// Pages Router
export async function getStaticProps() {
const data = await fetch('...')
return { props: { data } }
}// App Router
async function Page() {
const data = await fetch('...')
return
}
Dynamic routes:
// Pages Router
// pages/posts/[id].tsx// App Router
// app/posts/[id]/page.tsx
Component Migration
Server Components
- Default in App Router:
- Can be async
- No useState/useEffect
- Direct data fetching
- Smaller bundles
Client Components
- Mark with 'use client':
- Interactive elements
- Browser APIs
- Hooks (useState, useEffect)
- Event handlers
Composition Pattern
// Server Component
import { ClientButton } from './ClientButton'async function ServerPage() {
const data = await getData()
return (
{data.title}
)
}// Client Component
'use client'
export function ClientButton({ onClick }) {
return
}
Layout Migration
New Layout System
// app/layout.tsx - Root layout
export default function RootLayout({ children }) {
return (
{children}
)
}// app/dashboard/layout.tsx - Nested layout
export default function DashboardLayout({ children }) {
return (
{children}
)
}Common Challenges
1. Third-Party Libraries
- Some libraries need updates:
- Check compatibility
- Use 'use client' wrapper
- Find alternatives if needed
- Report issues to maintainers
2. Hooks Usage
- Server Components can't use hooks:
- Move to Client Components
- Use composition pattern
- Rethink data flow
3. CSS Solutions
- Some approaches change:
- CSS Modules work fine
- Tailwind works fine
- CSS-in-JS may need updates
- Check library docs
Migration Checklist
- Preparation:
- [ ] Update to latest Next.js
- [ ] Review breaking changes
- [ ] Plan migration order
- [ ] Set up parallel testing
- Execution:
- [ ] Create /app directory
- [ ] Add root layout
- [ ] Migrate pages incrementally
- [ ] Test each migration
- Completion:
- [ ] Remove /pages when done
- [ ] Update documentation
- [ ] Performance testing
- [ ] Monitor production
Migrating to App Router?
Our Next.js team has helped many teams make the transition smoothly. From planning to execution, we've got you covered.
Get Free Consultation →