Skip to content

Next.js Do's and Don'ts

This lesson is intentionally opinionated: short do/don't pairs that capture the lessons teams learn the hard way with the App Router.

Do Server-First, Don't Client-Default

If you remember one pair from this page: do start every feature as a Server Component, and don't sprinkle "use client" across whole pages to silence compiler errors. Extract the interactive piece instead.

Most other do/don't pairs follow the same theme — prefer framework conventions (page.tsx, Metadata API, next/image) over reinvented Patterns from the Pages Router or SPA era.

// DO
export default async function Page() {
  const data = await getData();
  return <List items={data} />;
}

// DON'T
"use client";
export default function Page() {
  const [data, setData] = useState([]);
  useEffect(() => {
    fetch("/api/data").then(...).then(setData);
  }, []);
  return <List items={data} />;
}

The "don't" example moves initial data loading to the client without need — slower first paint and worse SEO for public content.

Quick Reference Pairs

DO:  use next/link for internal navigation
DON'T: use <a> for internal routes (lose prefetch)

DO:  validate Server Action inputs
DON'T: trust FormData blindly

DO:  revalidatePath/Tag after mutations
DON'T: expect UI caches to update by magic
  • Do import navigation helpers from next/navigation in the App Router.
  • Don't mix Pages Router data APIs (getServerSideProps) into app/.
  • Do allow-list remote image hosts and use next/image.
  • Don't put secrets in NEXT_PUBLIC_ variables.

Do's and Don'ts Cheat Sheet

High-frequency decisions during feature work.

Do Don't
Keep "use client" at the edges Wrap entire layouts in Client Components
Use parallel Promise.all Chain independent awaits sequentially
Check auth in actions/handlers Rely on middleware alone for security
Use Metadata API per route Hardcode one title for the whole site
Read next build route symbols Assume every route is static

Routing Do's and Don'ts

File conventions are strict — follow them exactly.

  • Do name special files exactly page.tsx, layout.tsx, route.ts, error.tsx.
  • Don't create a route and a route.ts handler in the same segment.
  • Do use route groups (marketing) for organization without URL noise.
  • Don't expect @slot folders to appear in the URL path.

Data and Caching Do's and Don'ts

Caching surprises cause more production bugs than almost anything else.

  • Do set cache: "no-store" or revalidate intentionally for live data.
  • Don't assume fetch behaves exactly like browser fetch caching.
  • Do call revalidatePath / revalidateTag after Server Action writes.
  • Don't build an internal REST API solely so Server Components can read your own DB.

Common Mistakes

  • Importing useRouter from next/router inside the App Router.
  • Opening external links with target="_blank" patterns that don't apply — for Next, avoid inventing routers when <Link> exists.
  • Turning every form into a client-only SPA submission when a Server Action form works.
  • Copying Pages Router tutorials into an App Router codebase without checking APIs.

Key Takeaways

  • Server-first and convention-first beat reinventing SPA patterns inside Next.js.
  • Exact special filenames and App Router imports prevent a large class of bugs.
  • Explicit caching and revalidation beats hoping data "just updates".
  • Security checks belong in every mutation path, not only middleware.
  • When stuck, prefer the official App Router docs over outdated Pages Router posts.

Pro Tip

Keep a living do/don't list in your team wiki and update it whenever a production incident teaches a new lesson — institutional memory beats repeating the same Next.js footgun every quarter.