
Not a Tutorial, This is the Redemption Story of an App Router Hater in Next.js
M. Zakyuddin Munziri
@zakiego
Originally written in Bahasa Indonesia.
Once again, this is not a tutorial, but the redemption story of an App Router hater in Next.js. The language used may contain many technical terms, which will be linked to relevant documentation for easier understanding.
At the time of writing, the Next.js version used was version 13. However, this article was published right when Next.js version 14 was announced.
Introduction
App Router is a new paradigm introduced since version 13. If you're still using version 13 or below, you're most likely still using the Pages Router.
What's the difference?
The most noticeable difference is that App Router uses the /app folder to create pages. Meanwhile, Pages Router uses the /pages folder.
# Pages Router folder structure
├── package.json
├── pages
│ ├── _app.js
│ ├── index.js
│ ├── about.js
# App Router folder structure
├── package.json
├── app
│ ├── page.js
│ ├── layout.js
│ ├── about
│ │ ├── page.js
Discussion
The Concerns
At that time, I had just returned from KKN (community service program—still a student's fate 🥲). After spending a month as a village resident, being far away from any coding.
In the first meeting, Fikry and Sonny showed me a company project that was experimenting with App Router.
I thought to myself, "Bold move using App Router, I feel like there are still many people on Twitter who aren't comfortable with App Router, whether because of bugs or just complaints about it being weird" 😅.
However, since it was just a landing page, it was safe to experiment. It wasn't a complex system involving many interactions.
The code was still fully using use client. I shared this concern with Sonny, "So, if we use use client fully, what's the purpose of React Server Components then?". A question that I only recently found the answer to.
As a note, at the office we use Chakra-UI (yes, because it helps develop UI quickly!) as a component library. Unfortunately, Chakra-UI still requires use client to this day. Unlike Tailwind CSS which can be fully server-side.
First Steps

After some time, the moment came. I received a mandate to create a user management system, using Next.js App Router.
I had never even made a fun side project with App Router, and now I had to build something for serious purposes.
How did it feel? A mix of confidence and doubt in myself, would I succeed? 🙂
It didn't stop there. There was still something interesting. Usually, we used Prisma as the ORM and NextAuth.js for authentication, but this time we used new libraries. Not just new to us, but literally just born—freshly released to the market.
In tech Twitter terms, bleeding edge 🤣. Simply put, using new technology that hasn't been tested long in the market by developers, so there's a high risk of bugs. It could be bloody 🥶.
The libraries in question are Drizzle as the ORM and Lucia for authentication.
The Process
As I recall, before working on this serious project, I had read some articles by Nauval, which first touched my heart about App Router.
Days passed by. Reading the App Router documentation became my faithful companion. I rarely asked questions, preferring to find out myself, unless I was really stuck.
The ability to read documentation is very important, especially when learning the latest technology. Because usually, the first release is still in written form, with few video tutorials. Also, if compared, resources in written form are always more abundant than video.
My first step started with learning about forms. A lot of time was spent just learning how forms work directly with the server. How to use formData? How to create actions.ts?
During this process, there wasn't much progress on the UI. But once I started understanding how things work and found the patterns, the work felt easy, seriously.
At the End
About a month later, the main features of this user management project were complete. 🥳🎉
Unexpectedly, I who was initially doubtful about App Router, actually managed to complete a system with this paradigm.
Q&A
How do you feel, will you continue using App Router or go back to Pages Router?
With a thousand apologies, I've fallen for App Router. If asked to choose, I would stick with App Router.
After completing the project in this article, every time I create a new project, I always use App Router. I never init a project with Pages Router anymore.
What did you initially think was A, but turned out to be B, about App Router?
"use client" 😅
I initially thought that if a page uses use client, all components inside it would become client components too. Turns out that's not the case. Inside a page that uses use client, you can have components that are server components. 🤯
This is where the art lies—we can reduce the bundle load sent to the client. By rendering part of it on the server, and the rest is then handled by the client.
What feature made you fall in love with App Router?
There are actually many, one of them is the ease of accessing through the server, without having to use getServerSideProps. Check out the code below.
// app/dashboard/Header.tsx
// server component ☁️
async function getUser() {
const data = await fetch("/api/user").then((res) => res.json());
return data;
}
export function Header() {
const user = getUser();
return <p>{user.name}</p>;
}
// app/dashboard/page.tsx
// client component 🗻
'use client'
function Page() {
return (
<Header /> // this is a server component 😎
<Content />
<Footer />
);
}
Read slowly. We can place server components inside client components! So, we can avoid props drilling from getServerSideProps. Just place the fetch near the component that needs it.
Also, because we fetch on the server, we don't need to think about onLoading states when fetching on the client. And also, because fetching is done on the server, we can access the required .env without having to create a special API endpoint.
What about tRPC?
If you've ever read my Twitter bio (@zakiego), it says I'm a tRPC user.
But after using App Router, I no longer use it. I prefer using "use server" combined with Zod for validation.
If you have other questions, don't hesitate to ask! So they can be added to this section.
Takeaways
This is what the file structure looks like when using App Router now.

Explanation:
- action.ts for creating functions that run on the server.
- page-client.tsx for the page because Chakra UI is still fully client-side.
- page.tsx as the main place to put
<PageClient />, because page.tsx is what Next.js recognizes as a page. - schema.ts for placing the Zod schema which is then inferred and used in action.ts and page-client.ts for sending and receiving data.
Closing
Next.js just released new learning materials accessible through https://nextjs.org/learn. I highly recommend studying this official course.
In the end, whatever technology we choose, this discourse is only limited to fellow developers. While users don't care—what they want is an application that can be accessed without lag. 😅
Started writing on October 7, 2023 in Banjarmasin.
Completed on Friday afternoon, October 27, 2023 at Bambangin Village Office.


