PedroTech Next.js 15 App Architecture Method

Build a production-ready Next.js 15 application by correctly applying file-based routing, server vs client component selection, API routes, and metadata — without referencing the original course.

// TL;DR

The PedroTech Next.js 15 App Architecture Method is a decision framework for building production-ready Next.js 15 applications using the App Router. It teaches you how to structure file-based routing, choose between server and client components, fetch data directly in async server components, build API routes, and add SEO metadata correctly. Use it whenever you're scaffolding a new Next.js project, restructuring an existing one, or debugging routing, rendering, or data-fetching issues. It's especially valuable for developers migrating from the Pages Router or React SPAs who need to internalize Next.js 15's server-first conventions.

// When should you use the PedroTech Next.js 15 App Architecture Method?

Use this skill whenever you are scaffolding, structuring, or debugging a Next.js 15 project, or when deciding how to handle routing, data fetching, rendering strategy, or SEO metadata in a React-based web application.

// What do you need before applying this Next.js 15 method?

  • Project typerequired
    What kind of app are you building? (e.g., blog, e-commerce, dashboard, API-driven app)
  • Routes neededrequired
    List of pages/routes the app requires, including any dynamic segments
  • Data sources
    Where does data come from? (external API, database, static, etc.)
  • Interactivity requirements
    Which parts of the UI need user interaction, state, or browser events?
  • SEO importance
    Does this app need to rank in search engines? Which pages are SEO-critical?

// What are the core principles of Next.js 15 App Router architecture?

File-Based Routing

Every route in a Next.js app is defined by its folder name inside the app directory. The UI for that route lives in a file named page.tsx inside that folder. The folder name IS the URL segment — no separate router config needed.

Server Components by Default

Every component you create is a server component unless you explicitly add 'use client' at the top of the file. Server components render on the server, never execute on the client, and cannot use React hooks or browser interactivity.

Use Client Directive

Adding 'use client' at the very top of a file converts the entire file into a client component, enabling React hooks (useState, useEffect), browser events (onClick), and client-side interactivity.

Async Server Components for Data Fetching

Server components can be declared async, allowing you to await fetch calls or database queries directly inside the component body — no useEffect or separate API call needed.

Layout Wrapping

A layout.tsx file wraps all routes at its directory level and below. The root layout.tsx is non-negotiable and wraps the entire app. Nested layout.tsx files wrap only their route segment, enabling shared UI (navbars, sidebars) scoped to specific route groups.

Special File Names

Next.js reserves specific filenames that trigger framework behaviour: page.tsx (route UI), layout.tsx (wrapper), loading.tsx (loading state), error.tsx (error boundary), not-found.tsx (404 UI). Naming these files correctly IS the configuration.

Public Folder for Static Assets

Any file placed in the /public folder is directly accessible via its filename in the URL (e.g., /globe.svg) and can be referenced in code without relative path traversal, regardless of where the importing file lives.

API Routes via Route Files

Backend endpoints are created inside app/api/ using folder-based routing. Each endpoint folder contains a route.ts (not page.tsx). HTTP methods are exported as named async functions (GET, POST, PUT, DELETE) from that file.

Metadata as Exported Constant

SEO metadata is set by exporting a metadata constant from any page.tsx or layout.tsx that is a server component. This declaratively injects title, description, keywords, and social sharing tags into the page's HTML head — no manual head tag manipulation required.

Image Component Optimisation

Always use Next.js's Image component (from 'next/image') instead of a plain img tag. It handles size optimisation, lazy loading, and aspect-ratio stability automatically. External image domains must be whitelisted in next.config.ts under remotePatterns.

Client vs Server API Fetch URL Rule

When fetching your own API routes from a server component, you must provide the full absolute URL (e.g., using a NEXT_URL environment variable). Client components can use relative paths. Mixing these up is the most common beginner mistake.

// How do you build a Next.js 15 app step by step?

  1. 1

    Scaffold the project with create-next-app

    Run: npx create-next-app. Select: TypeScript=yes, ESLint=yes, Tailwind=yes (recommended), src directory=no, App Router=yes, Turbopack=yes, import alias=no (keep default @). The dot (.) as project name creates the app in the current folder.

  2. 2

    Understand and preserve the mandatory root files

    app/layout.tsx and app/page.tsx are non-negotiable. layout.tsx defines the HTML document shell and wraps all routes via {children}. page.tsx is the UI for the root (/) route. Never rename these. The component name inside page.tsx does not matter — only the filename matters.

  3. 3

    Plan and create your route folder structure inside /app

    For each route, create a folder whose name = the URL segment. Inside it, create page.tsx. For dynamic segments (e.g., /users/[id]), wrap the param name in square brackets: [userId]. Export a default function from each page.tsx. Keep non-route folders (components, lib, store) OUTSIDE the /app directory to avoid confusion.

  4. 4

    Add shared UI to layout.tsx, not to individual pages

    Anything placed outside {children} in layout.tsx appears on every route. Use this for navbars, footers, and global wrappers. Use Next.js's Link component (from 'next/link') for navigation — never plain anchor tags. For route-group-specific shared UI, create a nested layout.tsx inside that route's folder.

  5. 5

    Decide server vs client for every component

    Default: server component (no directive needed). Add 'use client' only when the component needs: useState, useEffect, onClick/onChange/any browser event handler, or any browser-only API. If a server component needs interactivity, extract ONLY the interactive piece into a separate client component file and import it into the server component.

  6. 6

    Fetch data in server components using async/await directly

    Make the page.tsx function async. Use await fetch() or await db.query() directly in the component body — no useEffect, no useState for loading. For dynamic route params, destructure params from props: const { userId } = await params. Type params as Promise<{userId: string}> in TypeScript.

  7. 7

    Add special-purpose files to handle loading, errors, and 404s

    loading.tsx in a route folder: shown while that route's data fetches. error.tsx in a route folder: shown when an error boundary is crossed. not-found.tsx in /app root: shown for any unmatched route or when you call the notFound() function (from 'next/navigation'). Call notFound() explicitly when fetched data returns empty to avoid rendering broken UI.

  8. 8

    Build backend endpoints in app/api/ using route.ts files

    Create: app/api/[endpoint-name]/route.ts. Export named async functions for each HTTP method: GET, POST, PUT, DELETE. Return responses using NextResponse.json() from 'next/server'. Access request body in POST with: const data = await request.json().

  9. 9

    Fix the server-component API fetch URL issue with environment variables

    Create a .env.local file (it is git-ignored by default). Add NEXT_URL=http://localhost:3000. When fetching your own API routes from a server component, prepend: ${process.env.NEXT_URL}/api/your-endpoint. Client components can use relative paths (/api/your-endpoint) without the base URL.

  10. 10

    Add metadata to every SEO-critical server component page

    Export a metadata constant from page.tsx or layout.tsx (server components only — client components cannot export metadata). Include: title, description, keywords array. For social sharing, add twitter: { card, title } and openGraph fields. Root layout.tsx metadata = global defaults. Page-level metadata overrides the global defaults for that route.

  11. 11

    Configure next.config.ts for external images and other settings

    To display images from external domains, add an images.remotePatterns array to next.config.ts with the hostname of each external source. This is the only required config change for most beginner projects. Experimental features and custom webpack config also live here.

// What do real Next.js 15 architecture decisions look like in practice?

A developer is building a blog with a homepage listing posts and individual post pages at /posts/[slug]

Create app/page.tsx for the homepage (server component, async, fetch posts directly). Create app/posts/[slug]/page.tsx for individual posts — destructure params to get slug, fetch the specific post, call notFound() if post is null. Add metadata export to each page.tsx with post-specific title and description. Add loading.tsx inside /posts/[slug]/ for the fetch loading state. Keep a Navbar component in /components/Navbar.tsx (outside /app) and render it in app/layout.tsx.

A SaaS dashboard that has a settings form requiring client-side state and validation

The /dashboard/settings/page.tsx can remain a server component that fetches the user's current settings. Extract the form itself into /components/SettingsForm.tsx with 'use client' at the top, enabling useState for form fields and onChange handlers. Import SettingsForm into the server page component. POST requests from the form use relative /api/settings path since it runs on the client.

An e-commerce site needing a /products route group with shared promotional banner UI

Create app/products/layout.tsx with the promotional banner component rendered above {children}. This banner appears automatically on /products, /products/[id], /products/category/[name] — all sub-routes — without adding it to each page individually. The root app/layout.tsx still handles the global navbar.

// What mistakes should you avoid when building a Next.js 15 app?

  • Using React hooks (useState, useEffect) inside a server component — this breaks the app. The fix: add 'use client' or extract the hook logic into a separate client component.
  • Using onClick or any browser event handler in a server component — server components are never executed on the client, so interactivity is impossible without 'use client'.
  • Fetching your own API routes from a server component using a relative path (e.g., /api/hello) — server-side fetches require the full absolute URL including the domain. Store this in NEXT_URL environment variable.
  • Placing non-route folders (components, lib, store) inside /app — Next.js treats every folder inside /app as a potential route segment, causing confusion. Keep utility and component folders outside /app.
  • Forgetting to whitelist external image hostnames in next.config.ts remotePatterns — the Image component will silently fail to load external images without this config.
  • Trying to export a metadata constant from a client component ('use client' file) — metadata export only works in server components. Mixing these causes silent metadata failures.
  • Naming the file page.js or route.js incorrectly — Next.js file-based routing is case and name sensitive. page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, route.ts must be named exactly.
  • Not handling empty API responses — if fetched data is null/undefined and you render properties on it, the app breaks. Always check for empty data and call notFound() or return an error state.
  • Using a plain anchor tag instead of the Link component for internal navigation — this causes full page reloads instead of client-side navigation, losing the performance benefits of Next.js routing.

// What key Next.js 15 terms do you need to know?

File-Based Routing
Next.js routing system where the folder name inside /app defines the URL segment, and a page.tsx file inside that folder defines the UI. No router configuration file is needed.
App Router
The current (recommended) routing system in Next.js, replacing the legacy Pages Router. All routes live inside the /app directory.
Server Component
The default component type in Next.js. Rendered entirely on the server; HTML is sent to the client. Cannot use React hooks, browser events, or client-side APIs. Can be async and fetch data directly.
Client Component
A component declared with 'use client' at the top of the file. Runs in the browser. Supports React hooks, useState, useEffect, and all browser interactivity.
use client
A directive placed at the very top of a file (before imports) that converts the entire module into a client component, enabling browser-only React features.
Async Server Component
A server component whose function is declared async, allowing direct use of await for data fetching or database queries inside the component body without useEffect.
layout.tsx
A reserved filename that defines a wrapper UI applied to all routes at its directory level and below. The root layout.tsx is mandatory and wraps the entire application.
page.tsx
A reserved filename that defines the UI rendered when a user navigates to the route defined by the parent folder. The exported component name is irrelevant — only the filename matters.
loading.tsx
A reserved filename placed inside a route folder. The component it exports is shown as a loading state while that route's data and UI are being fetched/rendered.
not-found.tsx
A reserved filename placed in the /app root that renders a custom 404 page for any unmatched route or when the notFound() function is programmatically called.
error.tsx
A reserved filename placed inside a route folder that renders a custom error UI when an error boundary is crossed in that route.
route.ts
The reserved filename used inside app/api/ subfolders to define backend API endpoints. HTTP methods are exported as named async functions (GET, POST, PUT, DELETE).
Dynamic Segment
A route folder whose name is wrapped in square brackets (e.g., [userId]) indicating that the URL value at that position is a variable parameter, accessible via the params prop.
params
A prop automatically injected by Next.js into page components inside dynamic segment folders. Returns a Promise (in Next.js 15) that resolves to an object keyed by the dynamic segment name.
remotePatterns
A configuration field in next.config.ts under the images key. Lists external hostnames from which the Next.js Image component is permitted to load images.
notFound()
A function imported from 'next/navigation' that, when called, programmatically triggers the not-found.tsx page — used to handle cases where fetched data is empty or invalid.
metadata
An exported constant from a server-component page.tsx or layout.tsx that declaratively defines SEO metadata (title, description, keywords, social tags) injected into the HTML head for that route.
Turbopack
A high-performance bundler built into Next.js (enabled via the --turbopack flag in the dev script) that significantly speeds up local development builds.
public folder
A top-level directory for static assets (images, SVGs, fonts). Files here are served directly at their filename path (e.g., /logo.png) and can be referenced without relative path traversal anywhere in the codebase.
lib folder
A conventional (not Next.js-enforced) top-level folder outside /app used to store utility functions, shared logic, and third-party library client instances (e.g., database clients, Stripe setup).

// FREQUENTLY ASKED QUESTIONS

What is the PedroTech Next.js 15 App Architecture Method?

It's a decision framework for building production-ready Next.js 15 apps using the App Router. It covers file-based routing, choosing server versus client components, fetching data in async server components, creating API routes, and adding SEO metadata. The method turns Next.js 15's conventions into repeatable rules so you can scaffold, structure, and debug apps without guessing.

What is a server component in Next.js 15?

A server component is the default component type in Next.js 15, rendered entirely on the server and sent to the client as HTML. It cannot use React hooks, browser events, or client-side APIs, but it can be declared async to fetch data or query a database directly in its body. Every component is a server component unless you add 'use client' at the top.

How do I decide between a server and client component in Next.js?

Default to a server component and add 'use client' only when you need useState, useEffect, onClick or other browser event handlers, or a browser-only API. If a mostly static page needs one interactive piece, extract only that piece into a separate 'use client' file and import it into the server component. This keeps most of your app server-rendered.

How do I fetch data in a Next.js 15 server component?

Make the page.tsx function async and use await fetch() or await db.query() directly in the component body — no useEffect or useState for loading. For dynamic routes, destructure params from props, typed as Promise<{ id: string }> in Next.js 15. Use loading.tsx for the loading state instead of manual loading flags.

How does the App Router compare to the old Pages Router?

The App Router uses folder-based routing inside /app where the folder name is the URL and page.tsx is the UI, with server components as the default. The legacy Pages Router used /pages with client-first rendering and getServerSideProps for data. App Router adds nested layouts, streaming, loading.tsx, and async server components — Pages Router lacks native server-component data fetching.

When should I use the Next.js Image component instead of an img tag?

Always use next/image for internal and external images because it handles size optimization, lazy loading, and aspect-ratio stability automatically. Plain img tags skip these benefits. For external image sources, you must whitelist each hostname in next.config.ts under images.remotePatterns, or the Image component will silently fail to load them.

How do I add SEO metadata to a Next.js 15 page?

Export a metadata constant from a server-component page.tsx or layout.tsx with title, description, and a keywords array. Add openGraph and twitter fields for social sharing. Root layout metadata sets global defaults; page-level metadata overrides them per route. Metadata export only works in server components — client components with 'use client' cannot export it.

When should I create an API route versus fetching directly in a server component?

Fetch directly in a server component when the page only reads data on the server. Create an API route in app/api/[name]/route.ts when the browser needs an endpoint — for form submissions, client-side mutations, webhooks, or third-party integrations. API routes export named async functions (GET, POST, PUT, DELETE) and return NextResponse.json().

What results can I expect from applying this method?

You get a correctly structured Next.js 15 app with server-rendered pages, scoped layouts, proper loading and error states, working API routes, and SEO metadata that injects into the HTML head. You avoid the most common beginner failures — hooks in server components, relative API URLs on the server, and unwhitelisted image domains — resulting in a faster, more maintainable, search-friendly application.

Why does my server component break when fetching my own API route?

Because server-side fetches require a full absolute URL, not a relative path. A relative path like /api/hello works only in client components running in the browser. In a server component, store your base URL in an environment variable (e.g., NEXT_URL) and prepend it: ${process.env.NEXT_URL}/api/hello. Mixing these up is the most common beginner mistake.

Can I put my components folder inside the app directory?

You shouldn't, because Next.js treats every folder inside /app as a potential route segment, which causes confusion and unexpected routes. Keep components, lib, and store folders outside /app at the project root. Only route folders with page.tsx and reserved files like layout.tsx, loading.tsx, error.tsx, and route.ts belong inside /app.

// GET THIS SKILL — FREE

Use this skill in your AI

Every skill on SkillForge is free. Drop your email and copy this skill straight into Claude, ChatGPT, or any LLM.

We'll email you when new skills drop. Unsubscribe anytime.