Bird
Raised Fist0
NextJSframework~20 mins

Server action database mutations 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 Action Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
component_behavior
intermediate
2:00remaining
What happens when this server action updates a record?

Consider this Next.js server action that updates a user's name in the database. What will be the rendered output after the update?

NextJS
import { revalidatePath } from 'next/cache';

export async function updateUserName(userId, newName) {
  await db.user.update({
    where: { id: userId },
    data: { name: newName }
  });
  revalidatePath('/users');
  return 'Update successful';
}

export default async function Page() {
  const message = await updateUserName(1, 'Alice');
  return <p>{message}</p>;
}
A<p>Update successful</p>
B<p>undefined</p>
C<p>Error: revalidatePath is not a function</p>
D<p>Loading...</p>
Attempts:
2 left
💡 Hint

Think about what the server action returns and how the component uses it.

📝 Syntax
intermediate
2:00remaining
Which option correctly defines a Next.js server action for deleting a post?

Identify the correct syntax for a server action that deletes a post by ID using Next.js conventions.

A
}
;)'stsop/'(htaPetadilaver  
;)} } dItsop :di { :erehw {(eteled.tsop.bd tiawa  
{ )dItsop(tsoPeteled noitcnuf cnysa tropxe
B
export function deletePost(postId) {
  db.post.delete({ where: { id: postId } });
  revalidatePath('/posts');
}
C
export async function deletePost(postId) {
  await db.post.delete({ where: { id: postId } });
  revalidatePath('/posts');
}
D
async function deletePost(postId) {
  await db.post.delete({ where: { id: postId } });
  revalidatePath('/posts');
}
Attempts:
2 left
💡 Hint

Remember to export the function and use the correct 'where' clause syntax.

🔧 Debug
advanced
2:00remaining
Why does this server action cause a runtime error?

Examine the server action below. Why does it cause a runtime error when called?

NextJS
export async function createUser(name) {
  const user = await db.user.create({
    data: { name }
  });
  revalidatePath('/users');
  return user;
}

// Called as createUser(); without arguments
ANo error, returns a user with empty name
BReferenceError: revalidatePath is not defined
CSyntaxError: Unexpected token 'await'
DTypeError: Cannot read property 'name' of undefined
Attempts:
2 left
💡 Hint

What happens if the function is called without the required argument?

state_output
advanced
2:00remaining
What is the state of the database after this server action runs?

This server action attempts to update a user's email but uses incorrect field names. What is the state of the database after running it?

NextJS
export async function updateUserEmail(userId, newEmail) {
  await db.user.update({
    where: { id: userId },
    data: { emailAddress: newEmail }
  });
  revalidatePath('/users');
  return 'Email updated';
}

// Assume 'email' is the correct field name in the database, not 'emailAddress'.
AThe user's email is updated to newEmail successfully.
BThe user's email remains unchanged; an error is thrown.
CA new user is created with the email newEmail.
DThe database is cleared of all users.
Attempts:
2 left
💡 Hint

Check the field names used in the update data object.

🧠 Conceptual
expert
2:00remaining
Which statement about Next.js server actions and database mutations is true?

Choose the correct statement about how Next.js server actions handle database mutations and cache updates.

AServer actions run on the server, perform database mutations, and can trigger cache invalidation with revalidatePath().
BServer actions automatically update the UI without needing revalidation or cache control.
CServer actions run on the client and directly mutate the database without cache updates.
DServer actions cannot perform database mutations; they only fetch data.
Attempts:
2 left
💡 Hint

Think about where server actions run and how cache is managed in Next.js.

Practice

(1/5)
1. What is the main purpose of using server actions for database mutations in Next.js?
easy
A. To run client-side animations after data changes
B. To securely update data on the server without exposing logic to the client
C. To fetch data from an external API on the client
D. To style components dynamically based on user input

Solution

  1. Step 1: Understand server actions role

    Server actions run on the server and handle data changes securely.
  2. Step 2: Identify the security benefit

    They keep mutation logic hidden from the client, preventing misuse.
  3. Final Answer:

    To securely update data on the server without exposing logic to the client -> Option B
  4. Quick Check:

    Server actions = secure server-side mutations [OK]
Hint: Server actions run on server to keep data safe [OK]
Common Mistakes:
  • Thinking server actions run on the client
  • Confusing server actions with client-side fetching
  • Believing server actions handle UI styling
2. Which of the following is the correct way to declare a server action function in Next.js?
easy
A. export async function addUser() { 'use server'; /* mutation code */ }
B. export async function addUser() { useServer(); /* mutation code */ }
C. export async function addUser() { /* mutation code */ } 'use server';
D. 'use server'; export async function addUser() { /* mutation code */ }

Solution

  1. Step 1: Identify correct 'use server' placement

    The 'use server' directive must be the first statement inside the function file or function scope.
  2. Step 2: Check syntax correctness

    'use server'; export async function addUser() { /* mutation code */ } places 'use server' at the top before the function, which is correct syntax.
  3. Final Answer:

    'use server'; export async function addUser() { /* mutation code */ } -> Option D
  4. Quick Check:

    'use server' directive must be at top [OK]
Hint: Put 'use server' at the top before function export [OK]
Common Mistakes:
  • Placing 'use server' inside function body after code
  • Using a function call like useServer() instead of directive
  • Putting 'use server' after function declaration
3. Given this server action code, what will be the result after calling await addUser({ name: 'Alice' }) if the database is empty?
 'use server';
 async function addUser(user) {
   await db.users.create({ data: user });
   return await db.users.count();
 }
medium
A. Returns 1 because one user is added
B. Returns undefined because no return statement
C. Throws an error because 'use server' is misplaced
D. Returns 0 because count is called before creation

Solution

  1. Step 1: Analyze database mutation

    The function creates a user in the database with given data.
  2. Step 2: Check return value

    After creation, it returns the count of users, which should be 1.
  3. Final Answer:

    Returns 1 because one user is added -> Option A
  4. Quick Check:

    Created one user, count = 1 [OK]
Hint: Create then count means count reflects new data [OK]
Common Mistakes:
  • Assuming count runs before creation completes
  • Confusing 'use server' placement causing error
  • Missing return statement in function
4. Identify the error in this server action code snippet:
'use server';
export async function updateUser(id, data) {
  await db.users.update({ where: { id }, data });
}
medium
A. Missing semicolon after 'use server' directive
B. Missing export keyword
C. Incorrect object structure in update call
D. No error, code is correct

Solution

  1. Step 1: Check 'use server' directive syntax

    The 'use server'; directive is correctly placed at the top of the module.
  2. Step 2: Analyze update method parameters

    The update method expects an object with 'where' and 'data' keys, but here 'data' is outside the object, causing syntax error.
  3. Final Answer:

    Incorrect object structure in update call -> Option C
  4. Quick Check:

    update expects { where: ..., data: ... } object [OK]
Hint: Check object keys carefully in db update calls [OK]
Common Mistakes:
  • Assuming missing semicolon causes error
  • Forgetting to wrap data inside update object
  • Missing export keyword (actually present)
5. You want to create a server action that deletes a user only if they have no active orders. Which approach correctly combines server action and database mutation logic?
 'use server';
 async function deleteUserIfNoOrders(userId) {
   const orders = await db.orders.findMany({ where: { userId, status: 'active' } });
   if (orders.length === 0) {
     await db.users.delete({ where: { id: userId } });
     return 'Deleted';
   }
   return 'Has active orders';
 }
hard
A. This code correctly checks orders before deleting user
B. This code deletes user without checking orders
C. This code will throw error because 'use server' is misplaced
D. This code returns 'Deleted' even if user has active orders

Solution

  1. Step 1: Verify order check logic

    The function queries active orders for the user and checks if none exist.
  2. Step 2: Confirm conditional deletion

    If no active orders, it deletes the user and returns 'Deleted'; otherwise returns 'Has active orders'.
  3. Final Answer:

    This code correctly checks orders before deleting user -> Option A
  4. Quick Check:

    Conditional delete based on orders = correct [OK]
Hint: Check conditions before mutation to avoid unwanted deletes [OK]
Common Mistakes:
  • Deleting user without checking orders first
  • Misplacing 'use server' directive
  • Returning wrong message ignoring condition