DEV Community

Cover image for šŸ˜µā€šŸ’« Server Components in Next.js 15: What I got wrong (and right)
Juanda MartĆ­nez
Juanda MartĆ­nez Subscriber

Posted on • Originally published at juanda.dev

šŸ˜µā€šŸ’« Server Components in Next.js 15: What I got wrong (and right)

This is a translated version of the original post published in my Spanish blog. The translation was generated using ChatGPT and manually reviewed for clarity and accuracy.

When I set out to build my personal blog with Next.js 15, I was excited to finally take advantage of the famous ✨ Server Components ✨. I had never really given them a proper try before, and I thought, ā€œThis is the future.ā€ What I didn’t know is that I was about to step into a world of bugs, broken builds, missing sessions, and documentation that was… confusing?

This post isn’t a tutorial — it's more of a story about how not to lose your mind when things don’t go as expected with Server Components, and how (unsurprisingly) AI can be overly agreeable unless you steer it toward the actual solution. Spoiler: I ended up learning more than I thought.


The first problem: the fetch that never came

It all started when my homepage, where I wanted to show the latest five blog entries, just… didn’t render anything. For context, I was using Next.js API routes with the App Router to handle the "backend" side of things.

The homepage is a server component generated statically at build time. It tries to fetch the latest posts via an internal API… but when I deployed it to Vercel, the build logs threw this error:

āŒ Internal Server Error

Error: Internal server error
    at a (.next/server/app/page.js:1:5127)
    at async p (.next/server/app/page.js:1:3031)

The build didn’t fail entirely, but the log was concerning. When I checked the live site, the list of posts was completely empty.

I thought this project would be "simple", but here I was — asking ChatGPT, then Grok because ✨ free tier ✨, taking a coffee-break ā˜•ļø when I finally remembered that I do have a brain, and that back in the day we used Google and StackOverflow to solve things. Then came the eureka moment:

How can I expect a static page to fetch posts from an API that **isn’t running yet?

It made total sense. Locally, the Node server is always running, so API routes are available. But during a deploy, when npm run build executes, there’s no server running yet — there’s nothing to fetch from.

The solution: I had to query the database directly from the Server Component. It feels like I’m breaking an abstraction, but it worked.


Session confusion

On another page, I needed to fetch an individual post. In this case, fetching from the internal API worked fine — it was also a Server Component, but the key difference is that this route is dynamic. It fetches data when someone visits the post. The server handles the query and sends back the full page. So far, so good.

The issue came when I needed to validate some logic based on the user's session. I kept trying different approaches, but the session inside the API routes always came as null.

And again… failed attempts asking an AI to solve my life. Something I could’ve solved if I had just read the official docs šŸ˜…

Still, I kept trying with Grok, trying to guide it toward the right idea. Here’s the prompt I used (don’t judge my broken English — I promise that I can do better, but since this thing is smarter than me, I don't bother to correct my grammatical issues 🤣):

it didn't work, still coming as null, but doesn't this have to do that I am using an internal API route to fetch a post, but this post is being fetched in a server component. I just tried to get the session data in the fetch itself and not inside my API routes and it worked

I know what you're thinking—I should’ve told the AI all of this context from the start. But in my experience, if you throw too much info at once, it ignores half of it and replies with whatever it wants anyway...

The solution: When doing fetch from a Server Component, the browser’s cookies šŸŖ are not sent automatically. And without cookies, there’s no session. You have to pass them manually—and thankfully, Next.js has the tools to do just that.

Note: This depends on the type of authentication your app uses. I use JWT (JSON Web Token) along with NextAuth.js, which stores session data in cookies.

import { cookies } from "next/headers";

const cookieStore = cookies();
const cookieString = cookieStore
  .getAll()
  .map((cookie) => `${cookie.name}=${cookie.value}`)
  .join("; ");

const response = await fetch(`http://localhost:3000/api/post/${params.id}`, {
  headers: {
    Cookie: cookieString,
  },
});
Enter fullscreen mode Exit fullscreen mode

āš ļø Docs - 1 | AI - 0

Since I'm apparently becoming a pseudo "vibe coder", let me highlight this moment where AI didn’t give the best answer.

In Grok’s response, it built a cookie string using .map and .join, which works. But if you look at the official Next.js docs, you’ll see the cookies() method already has a built-in .toString() that does this for you. So yeah... always double check šŸ‘ļø


So… what did I learn?

  1. Server Components are great, but full of gotchas. You need to understand where and how your code runs.

  2. Fetching your own API vs. querying the DB directly from Server Components is a nuanced decision. Context matters.

  3. Cookies aren't sent automatically with server-side fetch. If you need session data, pass cookies manually.

  4. Don't blindly rely on AI. Sometimes the old-school way (reading docs) saves you hours.

Things I could improve

It still feels a bit off to query the DB directly from a Server Component. If you also feel that ✨ itch thing ✨ when something seems wrong… trust it.

Every time I’ve ignored that gut feeling, I get code reviews or manager feedback pointing out exactly what I already suspected. I’m working on that — and this is a great chance to put it into practice.

šŸ’¬ I was looking through my Twitter bookmarks and found this tweet from @asidorenko_ explaining why you should separate your DB calls. I knew I’d read that somewhere.

Pro tip: when it comes to frontend, anything can be exposed—so be careful.


Uncle Juan's final thoughts

I remember when Server Components first showed up, the very nice and not-at-all toxic Twitter / X community was comparing them to old-school PHP, calling it a step backwards.

Personally (as with most tech trends), I didn’t jump on the hype train right away. I resisted Tailwind, daily AI use, search engine replacements, and Server Components (yep—my old Next.js projects always started with use client at the top). But eventually, I gave in. I tried them. And I liked them.

My point is: trying new things expands your understanding and helps you face real challenges. It's a good practice to reflect on the why behind what you're doing. Push yourself — try applying a design pattern or avoid using libraries for everything.

I once read (maybe on Reddit or Twitter) that a common question is: ā€œWhen should I use use client?ā€ The answer was simple: use server components by default, and only move the interactive parts to client components when absolutely necessary — even if it feels silly.

That advice stuck with me. And building my blog from scratch gave me the chance to follow it. It helped me write better component compositions (funny enough, there’s a React pattern called Composition that aligns perfectly with this approach). If I had just slapped use client everywhere, I wouldn’t have run into these issues — or learned from them.

That’s why experience matters when companies hire. It’s not just about knowing the concepts — it’s about the challenges you’ve faced and how you solved them. And that only comes from working on real-world projects that go beyond a JS calculator or a basic React to-do list.

šŸ’¬ While writing this post, I found another tweet by @asidorenko_ explaining how to separate the interactive part into a new component. I swear I’m not sponsored by him — go follow him if you're into Next.js content.

Also, look into the Composition pattern. Now that you've made it this far, you know it exists. You’ve probably already used it without realizing it. Being aware of it, studying it, and applying it consciously will score you points in interviews. šŸ˜‰


At the end of the day, this post is more of a war diary than a tutorial. But if I helped you save even a couple of hours of debugging, then it was all worth it.

Have you also wrestled with Server Components? Let me know—I’d love to hear your experience šŸ˜…

Suggestions and corrections are welcome—I'm far from perfect, but I’m not afraid to be transparent and show my thought process when tackling problems.

Top comments (0)