Course outline

Next.js / Basic: routes and execution boundaries / Lesson 2

File routes, layouts and async parameters

Compose route segments and shared layouts while awaiting request parameters under the selected Next 16 contract.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain page, layout, dynamic segment and route-group responsibilities.
  • Validate resolved params rather than trusting the path structure.

The directory tree is a public route contract

Within app, page.tsx makes a segment renderable and layout.tsx composes shared UI around its children. The root layout owns the document structure with html and body. Dynamic [id] segments supply runtime path values, while route groups in parentheses organize composition without adding that group name to the URL. These conventions do not authorize the data selected by a path. Keep public route shape, tenant scope and domain identity separate. A renamed folder can break links, metadata and retained clients just as changing an explicit router path would. Review the resulting URL rather than guessing it from every folder name.

Await route parameters before using their values

The page fragment uses a promise-valued params contract and awaits it before calling a server-only data helper. The helper is assumed to enforce eligibility and return a narrow card. Awaiting params does not validate id, establish a session or select a caching policy. Keep those decisions in explicit layers. The file path implied by the example is app/courses/[id]/page.tsx, but no file-based router or compiler was run. Next 16 requires the asynchronous access pattern rather than relying on older synchronous compatibility behavior.

tsx Illustrative async route page
export default async function CoursePage({params}:{params:Promise<{id:string}>}) {
  const {id}=await params;
  const card=await getVisibleCourseCard(id);
  return <h1>{card.title}</h1>;
}

The server helper, imports and JSX runtime are assumed. The example awaits params but was not compiled or rendered.

Shared layout lifetime is not per-page request freshness

Layouts can be reused during client navigation, so they should not be treated as a guaranteed place to rerun page-specific logic on every transition. Read current URL-derived state in the appropriate page or client hook rather than assuming a preserved layout sees a newly evaluated search parameter each time. A template has different remount behavior from a layout when that lifecycle is needed. Keep security checks in the data access and mutation boundaries even if a layout displays a sign-in gate. Hiding children in shared UI is not a substitute for protecting direct Route Handlers or Server Actions.

Validate a synthetic route identifier locally

The local predicate accepts lowercase course slugs with bounded hyphen-separated words. It rejects path-like input and repeated separators under this declared convention. Other APIs may choose opaque IDs or Unicode slugs; do not impose this lab grammar universally. URL decoding and catch-all parameter arrays are separate transport concerns. Validate the resolved shape before calling a source, and never turn a path string directly into a filesystem location. The assertions demonstrate a narrow identifier policy without executing Next params resolution or proving access to the referenced object.

javascript Complete offline slug-contract check
function validSlug(value) {return typeof value === "string" && value.length <= 60 && /^[a-z]+(?:-[a-z]+)*$/.test(value);}
console.assert(validSlug("server-components"));
console.assert(!validSlug("../private"));
console.assert(!validSlug("server--components"));

The declared course slug passes; path-like text and repeated separators fail. No route matching or decoding is tested.

Review groups, nesting and special cases as one tree

Retain fixtures for the root route, nested dynamic paths, missing segments, not-found behavior and any global base path. Route groups can create conflicting public paths if their pages resolve to the same URL. Catch-all and optional catch-all segments have different value shapes and root behavior. Place application code near routes deliberately without accidentally publishing a page convention in the wrong segment. This course checks only the slug function; layouts, templates, route-group resolution and asynchronous Next props remain unexecuted. A real isolated build and navigation test is needed to validate the actual route tree and preserved-state behavior.

Common errors and fixes

params.id is read synchronously

Why it happens
An older request-prop contract was copied into Next 16.
How to fix it
Await params under the selected page/handler contract.
Prevent it next time
Retain async-prop migration fixtures.

A route group unexpectedly changes a link assumption

Why it happens
Folder organization was confused with URL segments.
How to fix it
Review the resolved public route tree.
Prevent it next time
Test groups that map to the same public path.

A layout gate is called complete authorization

Why it happens
UI composition replaced source and mutation protection.
How to fix it
Enforce policy in each server entry and data layer.
Prevent it next time
Test direct handlers and actions as well as navigation.

Check your understanding

1. Does awaiting params make the course ID trustworthy?

Show worked solution

No. It resolves the frameworkโ€™s asynchronous value. The result still needs shape validation, object eligibility and a deliberate source contract. A valid slug can identify a forbidden course, so keep route parsing separate from authorization and test the same ID under eligible and ineligible callers.

2. Why not put every freshness and permission decision in a shared layout?

Show worked solution

Layouts can persist across client transitions, and other server entry points can bypass that UI. A layout can present navigation and user context, but the data layer and each mutation must enforce current authority independently. Test preserved layout state and direct entry behavior instead of assuming every click remounts the shared shell.

Key takeaways

  • File conventions compose URLs and UI lifetimes.
  • Resolved route values remain untrusted input.

Official references