Skip to content
Community content. Review instructions before giving them to an AI agent — treat modules like open-source code.

Next.js Project Conventions

App Router conventions: server-vs-client component defaults, safe env-variable exposure, and where data fetching and mutations belong.

Mby @markdownersPublished July 12, 2026 · Updated August 21, 2026 · ~2 min read

0 downloads · Used in: SaaS starter context

Project-level conventions for a Next.js (App Router) codebase, assuming Env & Secrets Hygiene@markdowners/env-and-secrets-hygiene's rules for anything env-related below, and Testing Strategy@markdowners/testing-strategy for how the test layout referenced here fits into the wider suite.

Server vs. client components

  • Default every component to a Server Component; add a client-component directive only to the specific leaf components that actually need interactivity, browser APIs, or React state/effects — pushing that directive to the top of a large tree drags everything beneath it into the client bundle unnecessarily.
  • Never import a server-only module (database client, secret-bearing SDK) into a file that's part of a client component's tree, even transitively — it either fails the build or, worse, gets bundled and shipped to the browser.

Data fetching

  • Fetch data directly in Server Components (async function components with await) rather than client-side effect-plus-fetch for anything that can be known at render time — it removes a client-side loading waterfall and keeps secrets/queries server-side.
  • Use route-level loading and error boundaries for granular, streaming-friendly loading and error UI instead of manual boolean state for every data-fetching component.

Environment variables

  • Only variables explicitly prefixed for client exposure (per the framework's convention) are safe in client-side code — every other variable is server-only by default and must stay that way; this specializes the general secrets-hygiene rule to Next.js's specific bundling behavior.
  • Validate required environment variables at startup (a small schema check run once) rather than discovering a missing variable via a runtime crash deep in a request handler.

File and folder structure

  • Colocate a route's own components, tests, and styles within its route segment folder; keep only genuinely shared, cross-route code in a top-level shared directory — this keeps "what does this route depend on" locally answerable.
  • Use route groups to organize routes without affecting the URL structure, rather than deeply nested folders that don't reflect the actual URL.

Server actions and mutations

  • Validate all input to a Server Action server-side (never trust that client-side form validation ran) — a Server Action is a public API endpoint with a different calling convention, not a trusted RPC.
  • Keep Server Actions focused (one mutation, one action) rather than a single catch-all action branching on a "type" parameter — it keeps authorization checks per-action instead of a branch that's easy to under-guard.

Metadata and rendering

  • Use the framework's typed metadata API per route rather than manually constructed head tags, so metadata stays server-rendered and type-checked.
  • Default to static/server rendering; opt into dynamic rendering deliberately (and know why) rather than accidentally forcing every route dynamic through an unnoticed uncached data call.

Requires

You might also add

Badge

Link back to this module from your own README.

Get it on Markdowners
[![Get it on Markdowners](https://markdowners.com/mdstack-badge.svg)](https://markdowners.com/m/markdowners/nextjs-project-conventions)

Comments (0)

Sign in to comment. Sign in

No comments yet. Be the first to add one.

Discussions about this module

No discussions about this module yet.

Start a discussion