Bird
Raised Fist0
NextJSframework~20 mins

Server component database queries in NextJS - Practice Problems & Coding Challenges

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Challenge - 5 Problems
🎖️
Server Component Query Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
Predict Output
intermediate
2:00remaining
What is the output of this server component fetching data?

Consider this Next.js server component that fetches user data from a database and renders the user's name.

import { db } from '@/lib/db';

export default async function UserName() {
  const user = await db.user.findFirst({ where: { id: 1 } });
  return <h1>{user?.name ?? 'Guest'}</h1>;
}

If the database has a user with id 1 and name 'Alice', what will this component render?

NextJS
import { db } from '@/lib/db';

export default async function UserName() {
  const user = await db.user.findFirst({ where: { id: 1 } });
  return <h1>{user?.name ?? 'Guest'}</h1>;
}
A<h1>Guest</h1>
B<h1>Alice</h1>
C<h1>undefined</h1>
DError: Cannot read property 'name' of undefined
Attempts:
2 left
💡 Hint

Think about what happens when the user is found and when it is not.

component_behavior
intermediate
2:00remaining
How does this server component behave with async database calls?

Given this Next.js server component:

import { db } from '@/lib/db';

export default async function ProductList() {
  const products = await db.product.findMany();
  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

What happens if the database query takes a long time?

NextJS
import { db } from '@/lib/db';

export default async function ProductList() {
  const products = await db.product.findMany();
  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}
AThe server component waits for the query before rendering the list.
BThe component renders immediately with empty list and updates later.
CThe component throws an error if the query is slow.
DThe component renders a loading spinner automatically.
Attempts:
2 left
💡 Hint

Remember server components run on the server and can await data before rendering.

🔧 Debug
advanced
2:00remaining
Why does this server component cause a hydration error?

Look at this server component fetching data and rendering a count:

import { db } from '@/lib/db';
import { useState } from 'react';

export default async function Counter() {
  const count = await db.count.findFirst();
  const [value, setValue] = useState(count.value);
  return (
    <div>
      <p>Count: {value}</p>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </div>
  );
}

Why does this cause a hydration error in Next.js?

NextJS
import { db } from '@/lib/db';
import { useState } from 'react';

export default async function Counter() {
  const count = await db.count.findFirst();
  const [value, setValue] = useState(count.value);
  return (
    <div>
      <p>Count: {value}</p>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </div>
  );
}
AServer components cannot use React hooks like useState.
BThe database query returns undefined causing a crash.
CThe component is missing a key prop on the button.
DThe async function does not return valid JSX.
Attempts:
2 left
💡 Hint

Think about the difference between server and client components in Next.js.

📝 Syntax
advanced
2:00remaining
Which option correctly fetches data in a Next.js server component?

Choose the correct syntax to fetch all posts from the database in a Next.js server component.

A
export default function Posts() {
  const posts = await db.post.findMany();
  return &lt;ul&gt;{posts.map(p =&gt; &lt;li key={p.id}&gt;{p.title}&lt;/li&gt;)}&lt;/ul&gt;;
}
B
export default async function Posts() {
  const posts = db.post.findMany();
  return &lt;ul&gt;{posts.map(p =&gt; &lt;li key={p.id}&gt;{p.title}&lt;/li&gt;)}&lt;/ul&gt;;
}
C
export default async function Posts() {
  const posts = await db.post.findMany();
  return &lt;ul&gt;{posts.map(p =&gt; &lt;li key={p.id}&gt;{p.title}&lt;/li&gt;)}&lt;/ul&gt;;
}
D
export default function Posts() {
  const posts = db.post.findMany();
  return &lt;ul&gt;{posts.map(p =&gt; &lt;li key={p.id}&gt;{p.title}&lt;/li&gt;)}&lt;/ul&gt;;
}
Attempts:
2 left
💡 Hint

Remember that await can only be used inside async functions.

🧠 Conceptual
expert
2:00remaining
Why should database queries be done in server components in Next.js?

In Next.js, why is it recommended to perform database queries inside server components rather than client components?

ADatabase queries in client components reduce server load by offloading work to the client.
BClient components can perform database queries faster because they run in the browser.
CServer components cannot fetch data, so queries must be done in client components.
DServer components run on the server, so queries are secure and do not expose credentials to the browser.
Attempts:
2 left
💡 Hint

Think about security and where code runs in Next.js.

Practice

(1/5)
1. What is the main advantage of using server components in Next.js for database queries?
easy
A. They fetch data securely on the server without exposing credentials to the client.
B. They allow direct database access from the browser.
C. They require no async/await syntax for queries.
D. They automatically cache data on the client side.

Solution

  1. Step 1: Understand server components role

    Server components run on the server, so they can safely access databases without exposing secrets to the client.
  2. Step 2: Compare options

    Only They fetch data securely on the server without exposing credentials to the client. correctly states the security advantage. Options A, C, and D are incorrect because database access is not done in the browser, async/await is needed, and caching is not automatic on client side.
  3. Final Answer:

    They fetch data securely on the server without exposing credentials to the client. -> Option A
  4. Quick Check:

    Server components = secure server data fetching [OK]
Hint: Server components run on server, so data stays secure there [OK]
Common Mistakes:
  • Thinking database queries run in the browser
  • Ignoring async/await for fetching data
  • Assuming client-side caching is automatic
2. Which of the following is the correct way to fetch data from a database inside a Next.js server component?
easy
A. const data = await db.query('SELECT * FROM users')
B. const data = fetch('api/data')
C. const data = db.query('SELECT * FROM users')
D. const data = useEffect(() => db.query('SELECT * FROM users'), [])

Solution

  1. Step 1: Identify async database query syntax

    Database queries inside server components must use async/await to wait for the query result.
  2. Step 2: Evaluate options

    const data = await db.query('SELECT * FROM users') uses await correctly. const data = fetch('api/data') uses fetch which is client-side. const data = db.query('SELECT * FROM users') misses await, so it returns a promise. const data = useEffect(() => db.query('SELECT * FROM users'), []) uses useEffect, which is a client hook and invalid in server components.
  3. Final Answer:

    const data = await db.query('SELECT * FROM users') -> Option A
  4. Quick Check:

    Async query = await db.query(...) [OK]
Hint: Use await with db queries inside async server components [OK]
Common Mistakes:
  • Omitting await causing unresolved promises
  • Using client hooks like useEffect in server components
  • Using fetch instead of direct DB queries
3. Given this Next.js server component code, what will be rendered if the database returns [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]?
export default async function Users() {
  const users = await db.query('SELECT id, name FROM users');
  return (
    <ul>
      {users.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  );
}
medium
A.
  • 1
  • 2
B.
  • Alice
  • Bob
C. Error: users.map is not a function
D.
  • {user.name}
  • {user.name}

Solution

  1. Step 1: Understand data and rendering

    The database returns an array of user objects with id and name. The component maps over users and renders each name inside <li>.
  2. Step 2: Check output correctness

    • Alice
    • Bob
    correctly shows the list with names Alice and Bob.
    • 1
    • 2
    shows ids instead of names. Error: users.map is not a function would happen if users was not an array.
    • {user.name}
    • {user.name}
    shows JSX code as text, which is incorrect.
  3. Final Answer:

    <ul><li>Alice</li><li>Bob</li></ul> -> Option B
  4. Quick Check:

    Mapping array to list items = names shown [OK]
Hint: Map array to JSX list to render names correctly [OK]
Common Mistakes:
  • Rendering ids instead of names
  • Forgetting to use key prop in list items
  • Trying to render raw objects instead of properties
4. Identify the error in this Next.js server component fetching data from a database:
export default function Products() {
  const products = await db.query('SELECT * FROM products');
  return (
    <div>{products.length} products found</div>
  );
}
medium
A. products.length is invalid for query result
B. Cannot use await inside server components
C. Missing async keyword on the component function
D. db.query should be inside useEffect hook

Solution

  1. Step 1: Check async usage in server component

    Await can only be used inside async functions. The component lacks the async keyword.
  2. Step 2: Validate other options

    Cannot use await inside server components is wrong because await is allowed in server components if async is used. db.query should be inside useEffect hook is wrong because useEffect is client-only. products.length is invalid for query result is wrong because products is expected to be an array with length.
  3. Final Answer:

    Missing async keyword on the component function -> Option C
  4. Quick Check:

    Await requires async function [OK]
Hint: Add async before function to use await inside [OK]
Common Mistakes:
  • Forgetting async keyword on server component
  • Using client hooks like useEffect in server components
  • Assuming query result is not an array
5. You want to fetch user data and their posts in a Next.js server component. Which approach correctly fetches both from the database before rendering?
export default async function UserPosts() {
  const user = await db.query('SELECT * FROM users WHERE id = 1');
  const posts = await db.query('SELECT * FROM posts WHERE userId = 1');
  return (
    <section>
      <h1>{user.name}</h1>
      <ul>
        {posts.map(post => <li key={post.id}>{post.title}</li>)}
      </ul>
    </section>
  );
}
What is the best way to optimize these queries?
hard
A. Fetch posts on the client side using useEffect
B. Run the second query inside the map function for posts
C. Combine both queries into one SQL join query
D. Run both queries in parallel using Promise.all before rendering

Solution

  1. Step 1: Understand query optimization

    Running queries sequentially waits for the first before starting the second, slowing response.
  2. Step 2: Evaluate options for optimization

    Run both queries in parallel using Promise.all before rendering runs both queries in parallel with Promise.all, improving speed. Run the second query inside the map function for posts runs queries inside map, causing many queries (bad). Fetch posts on the client side using useEffect moves fetching to client, losing server benefits. Combine both queries into one SQL join query is possible but may complicate data handling.
  3. Final Answer:

    Run both queries in parallel using Promise.all before rendering -> Option D
  4. Quick Check:

    Parallel queries = faster data fetching [OK]
Hint: Use Promise.all to fetch multiple queries simultaneously [OK]
Common Mistakes:
  • Running queries one after another sequentially
  • Fetching data inside loops causing many queries
  • Moving server data fetching to client side unnecessarily