next.js

The App Router went stable. My site did not move.

The App Router went stable. My site did not move.

Next.js 13.4 was announced on the fourth of May, and the headline was that the App Router is stable. That word was doing a lot of work — the App Router shipped in 13.0 last October as something you were told not to put in production, and plenty of people had been waiting for exactly this announcement before looking at it seriously.

I was one of them. This site runs on Next.js with a pages directory. I made a branch, spent a Saturday on it, and then deleted the branch. This is why, and the reason is not that the new router is bad.

Read the three labels carefully

The release contains three things at three different levels of maturity, and conflating them is how you end up somewhere uncomfortable.

App Router: stable. React Server Components, nested routes and layouts, colocated data fetching, streaming with Suspense, the metadata API. The recommendation from that release onward is that new applications use it.

Turbopack: beta. And specifically the dev server. Production builds are not part of that claim.

Server Actions: alpha. Mutating data on the server without shipping client JavaScript for it. Genuinely the most interesting idea in the release, and also the one explicitly labelled as not finished.

So "13.4 is stable" is true of the router and not of the two features most of the excitement was about.

The migration is not the folder

I assumed the work was moving files from pages/ to app/ and renaming a couple of data functions. That is the visible part and it is the small part.

The actual change is the default. In pages/, a component is a client component, and you opt into server work at the route level with getStaticProps or getServerSideProps. In app/, a component is a Server Component, and you opt out with 'use client' at the top of a file.

That inversion is the migration. Every piece of code that touches useState, useEffect, a context provider, an event handler, or the window object has to end up on the client side of a boundary you now have to place deliberately. The work is not rewriting pages. It is walking the component tree deciding where the line goes, and doing it again for every dependency that assumed it would run in a browser.

For an application with a handful of routes and a lot of interactivity, that is a real project rather than an afternoon. Which is fine — it is a better model, and better models cost something. But it should be priced honestly.

What this site actually is

A content site. Markdown files on disk, parsed at build time, rendered into static pages. getStaticProps reads the posts directory, the index page filters by tag and search in the browser, and nothing at all is fetched at request time.

Set the App Router's strengths against that list. Streaming and Suspense pay off when part of a page is slow and you want the rest of it sooner — nothing here is slow, because everything was computed at build time. Nested layouts pay off when chrome persists across navigation and you want to avoid re-rendering and re-fetching it — this site has a header and a footer. Colocated data fetching removes prop-drilling through page props — there are about four props.

The honest assessment is that migrating would buy me a better architecture for problems this codebase does not have, at the cost of a weekend and a stack of client boundaries, and the output would be the same static HTML.

What would change my mind

Three things, and I expect at least two of them.

The recommendation itself, over time. When new Next.js applications are built on the App Router by default, the Pages Router stops being the thing I know and starts being the thing I maintain. That gap widens on its own, and being fluent in the model everyone else is using has value independent of whether this particular site needs it.

Server Actions leaving alpha. This site has no mutations at all — the contact page is a set of mailto: links — so that one is about the next thing I build rather than this one. A mutation that does not ship its own client bundle is the right shape for a lot of small forms, and I am not putting an alpha under one.

Turbopack covering production builds. A faster dev server is pleasant; the build is where I actually wait.

The general rule I am taking away

A stable label tells you the maintainers are confident in their side of the contract. It does not tell you the migration is free, and it does not tell you that you need it.

The cost of moving is proportional to how much of your application assumed "client by default" — which for a heavily interactive app is most of it, and for a statically generated content site is simultaneously most of it and none of it, because almost nothing here is interactive in the first place.

I will move this site when there is a feature I want that I cannot have where I am. That is not today, and a version number going stable is not by itself a reason.

Deyan Peev

Written by

Deyan Peev

Founding Engineer · Sofia, Bulgaria

Deyan Peev

Founding Engineer in Sofia, Bulgaria. Currently at 1club.

Elsewhere

© 2026 Deyan Peev