My Experience Migrating from Next.js Page Router to App Router (Next.js v13)
Over the past week, I've been working to migrate this site over to Next.js v13 to reap the benefits of App Router. Along the way, I found a few hiccups, but mostly a smooth process with the strong documentation available on Next.js' developer site. I've always been a huge fan of the documentation available, and ultimately this should provide a great runway for developers to onboard to App Router or Next.js in general.
Primary App Router Benefits
Layouts in App Router provide a great structure for managing cached content across multiple pages, while still providing flexibility to allow for sub-layouts where needed. After working through an initial Root Layout bug, or rather what I thought was a bug but was due to me wrapping my Page content in a
RootLayout element (this caused my header to be duplicated across pages), I immediately saw the benefit of having shared layouts across the application.
Keeping a Root Layout, while altering at the page level will provide this rebuild a cached header/navigation experience as they continue browsing the site for dynamic or uncached content. Bringing this use case to my main line of work at VTEX, an example could be providing a cached navigation experience across the entire application while loading dynamic components through ISR strategies, or other rendering strategies when dealing with something like thousands of products to load for PDPs, etc. https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#layouts
Granularity in Fetching Data
One of the biggest benefits of migrating to App Router comes in the form of being able to delegate the fetching of data to the component level. App Router now focuses on Server and Client components, where Server components can still reap the benefits of Static Site Generation (SSG) and caching of that content, while also delegating client interactions to Client Components, where state being used was my primary use-case for that. My only client component in this entire site ended up being my
Header.tsx where I leverage state for a mobile navigation menu. Another benefit of shared Layouts includes sharing that state across the entire site as a user navigates between pages.
As you work with Server Components, the default behavior is to fetch data and cache that across the application to share with other components through memoization. This is an incredibly power feature to provide a simple and granular data fetching strategy.
App Dir Structure
The new App Dir structure for App Router brings a structured approach to managing Pages, Layouts, and the overall router structure. Page router, in my opinion, was a bit more friendly to newer developers working with Next.js. The new App Router file structure, however, follows a semantic approach you can see in the image below.
To start, you have a root page and root layout file. This layout acts as your Root Layout for the entire site, though you can also delegate layout support to the route level. For each route, you can define a folder that contains a page file as well, and a layout file if you do need more granular layout support. Dynamic routes still use a [ ] approach, but now the variable that will drive your page is called out at the folder level, again with a page file that will contain dynamic routing logic.
Next.js has continued to provide a more seamless support structure for Typescript, and v13 and the current
npx create-next-app@latest CLI toolset/app setup has a great workflow to automatically setup your Typescript config file and overall app support. Coming from v10 / v11, the process to step into this seems far better with v13.
Diving into App Router has pushed me to want to eventually move HomeKitchen, my current Recipe SaaS application being worked on, over from Page Router. The benefits of data fetching strategies and the Server/Client component structure would have been (and will be) tremendously impactful in the application architecture I would have been able to build from the start.