Product search started returning 404s after migrating. Turns out next/router
doesn't exist anymore. Vercel deleted the entire fucking package in Next.js 13.4.0. Not deprecated - gone.
// This worked fine yesterday
import { useRouter } from 'next/router'
const router = useRouter()
const { productId, category } = router.query // RIP
Now you need three different imports to do what one hook used to do:
'use client'
import { useRouter, useSearchParams, useParams } from 'next/navigation'
// useRouter() only pushes routes now
// useSearchParams() for ?category=shoes
// useParams() for /products/[id]
The router.isReady
property? Gone. No replacement. Delete every router.isReady
check because it doesn't exist anymore.
Middleware Stops Working (Zero Error Messages)
Spent 4 hours debugging why auth stopped working. No error messages. No console logs. Middleware just... stopped running.
Turns out you can't put middleware inside app/
anymore. Has to be in project root:
project/
├── app/
├── middleware.ts ← Only works here, nowhere else
└── package.json
In Pages Router, middleware ran on everything by default. App Router middleware needs explicit path matching or it won't run at all:
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico).*),'
],
}
This broke our auth routes silently. Users could access protected pages without logging in. Production was fucked for 2 hours before I realized middleware wasn't running at all. Zero logs. Zero errors. Just silently failing.
Error Pages Are Now Error... Hierarchies?
Your simple 404.js
file doesn't work anymore. App Router uses multiple error files:
error.tsx
for component crashesnot-found.tsx
for 404sglobal-error.tsx
for root layout errors
Server component errors happen during rendering and show generic production error pages. Error boundaries only catch client component errors. Learned this when our dashboard crashed and users saw "Application error: a client-side exception has occurred" instead of our custom error page.
Auth Libraries Had to Start Over
NextAuth.js v4 doesn't work with App Router. At all. v5 rewrote the entire API. Every authentication pattern we had needed rewriting.
Session handling split into multiple APIs. Server components use auth()
, client components use useSession()
, middleware gets sessions differently. Nothing from v4 works anymore.
Clerk, Auth0, and Supabase all have separate App Router guides now because their old patterns broke too.
Development Lies to You
Everything works in next dev
, then production breaks. Development and production behave completely differently in App Router.
Our dashboard worked fine locally, then 404'd in production. Took 2 hours to realize it was trying to fetch from localhost:3000 during the build process. Dynamic routes get statically generated at build time unless you tell them not to.
Always run npm run build && npm start
before deploying. The development server uses different rendering strategies than production. I learned this the hard way when our client's site went down on launch day. Took 3 hours to roll back and another 4 hours to figure out what the hell happened.