Skip to Content
Exercises03 Next.jsExercise: App Router boundaries (server vs client)

Exercise: App Router boundaries (server vs client)

Goal

Build a small Next.js App Router feature that forces correct server/client separation and good UX states.

Scenario

Create a “Users” page with:

  • a server-rendered list (data loaded server-side)
  • a client-side form to add a user (interactive)
  • loading + error states

Requirements

  • Routing/layout:
    • Use App Router (app/).
    • Add a shared layout for the section (title + nav).
  • Server/client separation:
    • The list is rendered from a Server Component.
    • The form is a Client Component.
  • UX states:
    • Show a loading state while data is loading.
    • Show a user-friendly error state if loading fails.
    • After creating a user, the list updates (strategy is up to you).

Data rules (for now)

  • You may use an in-memory “fake” data source on the server side (module-level array) to keep this exercise focused.
  • Do not call a “microservice” from the browser. Pretend the server data source is the microservice boundary.

Acceptance criteria (entry)

  • No "use client" at the page level unless it’s strictly required (it shouldn’t be).
  • Data access is server-side only.
  • Form is interactive and handles disabled/loading/error states.

Stretch goals (mid)

  • Add Zod validation for the form:
    • client-side UX mapping
    • server-side boundary validation (even if the “server” is a fake layer)
  • Add optimistic UI (with rollback on error) or a clear refresh strategy.

Stretch goals (senior)

  • Write down a boundary decision for when to use:
    • Server Components
    • Client Components
    • Route Handlers
    • tRPC procedures in this scenario.
Last updated on