Server components let you fetch data directly from a database on the server. This keeps your app fast and secure by not sending database code to the browser.
Server component database queries in NextJS
Start learning this pattern below
Jump into concepts and practice - no test required
export default async function Page() { const data = await fetchDataFromDatabase(); return ( <main> {/* Render data here */} </main> ); }
Server components use async functions to wait for data before rendering.
You can import database helpers directly in server components.
import { getUsers } from '@/lib/db'; export default async function UsersPage() { const users = await getUsers(); return ( <ul> {users.map(user => <li key={user.id}>{user.name}</li>)} </ul> ); }
import { db } from '@/lib/prisma'; export default async function PostList() { const posts = await db.post.findMany(); return ( <section> {posts.map(post => ( <article key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> </article> ))} </section> ); }
This server component fetches all products from the database using Prisma. It then shows each product's name and price in a list.
import { db } from '@/lib/prisma'; export default async function ProductList() { const products = await db.product.findMany(); return ( <main> <h1>Products</h1> <ul> {products.map(product => ( <li key={product.id}> {product.name} - ${product.price} </li> ))} </ul> </main> ); }
Server components run only on the server, so you can safely use database credentials here.
Do not use client-side hooks like useState or useEffect in server components.
Always await your database calls to ensure data is ready before rendering.
Server components let you fetch and render database data safely on the server.
Use async functions and await database queries inside server components.
This approach improves security and performance by keeping data fetching server-side.
Practice
Solution
Step 1: Understand server components role
Server components run on the server, so they can safely access databases without exposing secrets to the client.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.Final Answer:
They fetch data securely on the server without exposing credentials to the client. -> Option AQuick Check:
Server components = secure server data fetching [OK]
- Thinking database queries run in the browser
- Ignoring async/await for fetching data
- Assuming client-side caching is automatic
Solution
Step 1: Identify async database query syntax
Database queries inside server components must use async/await to wait for the query result.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.Final Answer:
const data = await db.query('SELECT * FROM users') -> Option AQuick Check:
Async query = await db.query(...) [OK]
- Omitting await causing unresolved promises
- Using client hooks like useEffect in server components
- Using fetch instead of direct DB queries
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>
);
}Solution
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>.Step 2: Check output correctness
- Alice
- Bob
- 1
- 2
- {user.name}
- {user.name}
Final Answer:
<ul><li>Alice</li><li>Bob</li></ul> -> Option BQuick Check:
Mapping array to list items = names shown [OK]
- Rendering ids instead of names
- Forgetting to use key prop in list items
- Trying to render raw objects instead of properties
export default function Products() {
const products = await db.query('SELECT * FROM products');
return (
<div>{products.length} products found</div>
);
}Solution
Step 1: Check async usage in server component
Await can only be used inside async functions. The component lacks the async keyword.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.Final Answer:
Missing async keyword on the component function -> Option CQuick Check:
Await requires async function [OK]
- Forgetting async keyword on server component
- Using client hooks like useEffect in server components
- Assuming query result is not an array
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?Solution
Step 1: Understand query optimization
Running queries sequentially waits for the first before starting the second, slowing response.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.Final Answer:
Run both queries in parallel using Promise.all before rendering -> Option DQuick Check:
Parallel queries = faster data fetching [OK]
- Running queries one after another sequentially
- Fetching data inside loops causing many queries
- Moving server data fetching to client side unnecessarily
