Back to Blog
Lesson 22 of the Next.js: Build Full-Stack Apps with the App Router course
Next.jsAugust 9, 20263 min read

Fetching Data from the Database in Next.js Server Components

Learn how to query your database directly in Next.js Server Components. We'll cover mapping database records to UI and handling empty states gracefully.

Next.jsPrismaDatabaseServer ComponentsWeb Development
Close-up of tower servers in a data center with blue and red lighting.

Previously in this course, we covered Database Setup with Prisma and Seeding Data. Now that your local database is populated with data, it's time to stop using hardcoded arrays and start fetching real information directly into your components.

In Next.js, because Server Components run on the server, you can perform database queries directly inside your component files. This architecture simplifies your data pipeline significantly.

Querying the Database in Server Components

To fetch data, you'll import your Prisma client instance and use it within an async function inside your page or component. Because these are Server Components, you don't need to worry about useEffect or external API routes for simple data retrieval.

Here is how you update your blog homepage to fetch posts from the database:

TSX
// app/page.tsx
import { prisma } from "@/lib/prisma"; // Your prisma client instance
import PostCard from "@/components/PostCard";

export default async function HomePage() {
  // 1. Fetch data directly from the database
  const posts = await prisma.post.findMany({
    orderBy: { createdAt: CE9178">'desc' },
  });

  // 2. Handle empty states
  if (posts.length === 0) {
    return <p>No blog posts found. Check back later!</p>;
  }

  // 3. Map data to the UI
  return (
    <main className="grid gap-6">
      {posts.map((post) => (
        <PostCard key={post.id} post={post} />
      ))}
    </main>
  );
}

Mapping Data to UI

When mapping data, always ensure your key prop is unique—the database id is perfect for this. Server Components allow you to pass complex objects directly from the database to your child components, which is a significant developer experience upgrade compared to traditional client-side fetching.

If you find yourself fetching the same data in multiple places, remember to leverage Mastering Request Memoization in Next.js for Optimized Server Components to keep your app performant.

Handling Empty States

Production apps rarely have perfectly populated data. Always account for the "zero state." If your findMany call returns an empty array, the user shouldn't see a broken page or a blank screen.

StateStrategy
LoadingUse loading.js to show a skeleton screen.
EmptyReturn a user-friendly "No content" message.
ErrorUse error.js to catch database connection issues.

Hands-on Exercise

  1. Open your app/page.tsx file.
  2. Import your prisma client.
  3. Change your HomePage function to async.
  4. Replace your static posts array with a await prisma.post.findMany() query.
  5. Add an if check to handle the case where the database is empty.
  6. Ensure your PostCard component receives the post prop and renders the title and date.

Common Pitfalls

  • Forgetting async: Server Components performing database queries must be async. If you forget this, you will receive an error because you are trying to await a promise in a non-async function.
  • Over-fetching: Don't select everything if you only need the title and slug. Use the select or include options in your Prisma query to keep payload sizes small.
  • Mixing Logic: Keep your database calls at the top level of the Server Component. Avoid nesting data fetching inside deeply rendered UI components if possible; instead, use Next.js App Router Parallel Data Fetching with Suspense to keep your page structure clean.

Recap

We've successfully moved from static data to dynamic database queries. By using async Server Components, we've reduced complexity and eliminated the need for client-side API calls. Always remember to handle empty array results to provide a polished experience for your users.

Up next: Implementing Comment Functionality, where we will expand our schema and create forms to add data to our blog.

Similar Posts