Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Templates Vs Layouts
Your Progress0%
0 of 70 completed

NextJS Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication

Templates vs Layouts

Understanding when to use template.tsx instead of layout.tsx

Layouts are great for persistent UI, but what if you want something to re-render on every navigation? Maybe you need to reset a form, replay an animation, or track page views. That's where templates come in. Templates look like layouts but behave differently: they create a new instance on every navigation, resetting all state and effects. Understanding this subtle but crucial difference will help you choose the right tool for each scenario.

The Key Difference

layout.tsx

  • Persists across page navigations
  • State is maintained
  • DOM elements stay mounted
  • useEffect runs once
  • Better for performance
  • Default choice for most cases

template.tsx

  • Re-renders on every navigation
  • State is reset
  • DOM elements remount
  • useEffect runs every time
  • Slight performance cost
  • Special cases only

Simple Rule of Thumb

If you want UI to persist (most cases) → use layout.tsx

If you want UI to reset (rare cases) → use template.tsx

Visual Comparison: Behavior Difference

Let's see the difference with a counter example:

With layout.tsx (Persists)

app/with-layout/layout.tsx
'use client';

import { useState } from 'react';
import Link from 'next/link';

export default function PersistentLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  // This state PERSISTS when navigating between pages
  const [count, setCount] = useState(0);

  return (
    <div className="p-8">
      <div className="mb-6 bg-blue-50 border-2 border-blue-500 p-4 rounded">
        <h2 className="font-bold mb-2">Layout (Persists)</h2>
        <p className="mb-2">Count: {count}</p>
        <button
          onClick={() => setCount(count + 1)}
          className="px-4 py-2 bg-blue-600 text-white rounded"
        >
          Increment
        </button>
        <p className="text-sm text-gray-600 mt-2">
          ↑ This count stays the same when you navigate
        </p>
      </div>

      <nav className="flex gap-4 mb-6">
        <Link href="/with-layout/page-1" className="text-blue-600">
          Page 1
        </Link>
        <Link href="/with-layout/page-2" className="text-blue-600">
          Page 2
        </Link>
      </nav>

      {children}
    </div>
  );
}

Behavior: Click increment, then navigate between pages. The count stays the same because the layout persists.

With template.tsx (Re-renders)

app/with-template/template.tsx
'use client';

import { useState } from 'react';
import Link from 'next/link';

export default function ResetTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  // This state RESETS when navigating between pages
  const [count, setCount] = useState(0);

  return (
    <div className="p-8">
      <div className="mb-6 bg-purple-50 border-2 border-purple-500 p-4 rounded">
        <h2 className="font-bold mb-2">Template (Re-renders)</h2>
        <p className="mb-2">Count: {count}</p>
        <button
          onClick={() => setCount(count + 1)}
          className="px-4 py-2 bg-purple-600 text-white rounded"
        >
          Increment
        </button>
        <p className="text-sm text-gray-600 mt-2">
          ↑ This count resets to 0 when you navigate
        </p>
      </div>

      <nav className="flex gap-4 mb-6">
        <Link href="/with-template/page-1" className="text-blue-600">
          Page 1
        </Link>
        <Link href="/with-template/page-2" className="text-blue-600">
          Page 2
        </Link>
      </nav>

      {children}
    </div>
  );
}

Behavior: Click increment, then navigate between pages. The count resets to 0 because the template re-renders.

Layouts vs Templates File Structure

See the difference in file names and behavior

appImportant

Select a file or folder to see details

When to Use Templates

Templates are useful in specific scenarios:

1. Page View Analytics

Track every page view with useEffect that runs on each navigation:

app/template.tsx
'use client';

import { useEffect } from 'react';
import { usePathname } from 'next/navigation';

export default function AnalyticsTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  const pathname = usePathname();

  useEffect(() => {
    // This runs on EVERY page navigation
    analytics.track('page_view', { path: pathname });
    console.log('Page viewed:', pathname);
  }, [pathname]);

  return <>{children}</>;
}

2. Enter/Exit Animations

Animations that should replay on each page:

app/template.tsx
'use client';

import { motion } from 'framer-motion';

export default function AnimatedTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -20 }}
      transition={{ duration: 0.3 }}
    >
      {children}
    </motion.div>
  );
}

3. Resetting Forms or State

Forms that should clear when navigating away:

app/search/template.tsx
'use client';

import { useState } from 'react';

export default function SearchTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  // This resets when navigating to a different search category
  const [query, setQuery] = useState('');

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
        className="w-full px-4 py-2 border rounded mb-4"
      />
      {children}
    </div>
  );
}

4. Focus Management

Automatically focus an input on page load:

app/template.tsx
'use client';

import { useEffect, useRef } from 'react';

export default function FocusTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    // Focus management on each navigation
    ref.current?.focus();
  }, []);

  return (
    <div ref={ref} tabIndex={-1}>
      {children}
    </div>
  );
}

Use Templates Sparingly

Templates have a performance cost since they re-render on every navigation. Only use them when you specifically need the re-rendering behavior. Layouts are the default choice for most cases.

Using Layouts and Templates Together

You can use both in the same folder. The rendering order is:

PLAINTEXT
<Layout>
  <Template>
    {children}
  </Template>
</Layout>

The layout wraps the template, which wraps the page content.

Example: Persistent Sidebar + Animated Content

app/blog/layout.tsx
// This persists across navigation
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex">
      {/* Sidebar stays mounted */}
      <aside className="w-64 p-6">
        <h3>Categories</h3>
        {/* ... sidebar content ... */}
      </aside>

      {/* Content area (includes template) */}
      <main className="flex-1">
        {children}
      </main>
    </div>
  );
}
app/blog/template.tsx
'use client';

import { motion } from 'framer-motion';

// This re-renders on every navigation
export default function BlogTemplate({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      transition={{ duration: 0.3 }}
    >
      {children}
    </motion.div>
  );
}

Result: The sidebar persists (no re-render), but the content area fades in on each navigation!

Lifecycle Comparison

Layout Lifecycle

TYPESCRIPT
'use client';

import { useEffect, useState } from 'react';

export default function Layout({ children }) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    console.log('Layout mounted');
    setMounted(true);

    return () => {
      console.log('Layout unmounted');
    };
  }, []); // Runs ONCE when first rendered

  console.log('Layout render');

  return <div>{children}</div>;
}

// Navigation between pages under this layout:
// First visit: "Layout render" → "Layout mounted"
// Navigate to sibling: "Layout render" (no unmount!)
// Navigate away: "Layout unmounted"

Template Lifecycle

TYPESCRIPT
'use client';

import { useEffect, useState } from 'react';

export default function Template({ children }) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    console.log('Template mounted');
    setMounted(true);

    return () => {
      console.log('Template unmounted');
    };
  }, []); // Runs on EVERY navigation

  console.log('Template render');

  return <div>{children}</div>;
}

// Navigation between pages:
// First visit: "Template render" → "Template mounted"
// Navigate to sibling: 
//   "Template unmounted" → "Template render" → "Template mounted"
// Every navigation triggers full lifecycle!

Practical Examples

Example 1: Multi-Step Form

Use layout for persistent progress, template for resetting each step:

app/checkout/layout.tsx
'use client';

import { useState } from 'react';

// Layout: Persistent progress tracker
export default function CheckoutLayout({ children }) {
  const [completedSteps, setCompletedSteps] = useState<string[]>([]);

  return (
    <div>
      {/* Progress bar persists */}
      <div className="mb-6">
        <div className="flex gap-4">
          {['Info', 'Shipping', 'Payment'].map((step) => (
            <div
              key={step}
              className={`flex-1 p-3 rounded ${
                completedSteps.includes(step)
                  ? 'bg-green-100'
                  : 'bg-gray-100'
              }`}
            >
              {step}
            </div>
          ))}
        </div>
      </div>

      {children}
    </div>
  );
}
app/checkout/template.tsx
'use client';

// Template: Each step's form resets
export default function CheckoutTemplate({ children }) {
  // Form state resets when navigating to next step
  return (
    <div className="animate-fadeIn">
      {children}
    </div>
  );
}

Example 2: Dashboard with Live Updates

app/dashboard/layout.tsx
'use client';

import { useEffect, useState } from 'react';

// Layout: Persistent WebSocket connection
export default function DashboardLayout({ children }) {
  const [notifications, setNotifications] = useState<string[]>([]);

  useEffect(() => {
    // WebSocket stays connected
    const ws = new WebSocket('wss://api.example.com');
    
    ws.onmessage = (event) => {
      setNotifications(prev => [...prev, event.data]);
    };

    return () => ws.close();
  }, []); // Only runs once

  return (
    <div>
      {/* Notification bell persists */}
      <header>
        <div>🔔 {notifications.length}</div>
      </header>
      {children}
    </div>
  );
}
app/dashboard/template.tsx
'use client';

import { useEffect } from 'react';

// Template: Track page views
export default function DashboardTemplate({ children }) {
  useEffect(() => {
    // Runs on every page navigation
    trackPageView();
  }, []);

  return <>{children}</>;
}

Best Practices

1. Default to Layouts

Use layout.tsx as your default. Only switch to template.tsx when you specifically need re-rendering behavior.

2. Document Template Usage

TYPESCRIPT
// app/section/template.tsx

/**
 * TEMPLATE: Used instead of layout because:
 * - Need to track page views on every navigation
 * - Form state should reset between pages
 * - Animations should replay on each page
 */
export default function Template({ children }) {
  // ...
}

3. Combine Strategically

PLAINTEXT
// ✅ Good: Layout for persistent UI, template for animations
app/blog/
  layout.tsx    ← Sidebar (persists)
  template.tsx  ← Fade animation (re-renders)

// ❌ Unnecessary: Both doing same thing
app/section/
  layout.tsx    ← Just structure
  template.tsx  ← Also just structure (redundant)

4. Consider Performance

TYPESCRIPT
// ❌ Bad: Expensive operations in template
export default function Template({ children }) {
  const data = expensiveCalculation(); // Runs on EVERY nav
  return <div>{children}</div>;
}

// ✅ Good: Move expensive ops to layout
export default function Layout({ children }) {
  const data = expensiveCalculation(); // Runs ONCE
  return <div>{children}</div>;
}

5. Be Explicit About State Reset

TYPESCRIPT
// Add clear comments when using templates
export default function SearchTemplate({ children }) {
  // State resets on navigation - this is intentional
  // User's search should clear when switching categories
  const [query, setQuery] = useState('');
  
  return <>{children}</>;
}

Common Mistakes

Mistake 1: Using Template When Layout Would Work

TYPESCRIPT
// ❌ Bad: No reason for template here
// app/blog/template.tsx
export default function Template({ children }) {
  return (
    <div className="container">
      <aside>Sidebar</aside>
      <main>{children}</main>
    </div>
  );
}

// ✅ Good: Just use layout
// app/blog/layout.tsx
export default function Layout({ children }) {
  return (
    <div className="container">
      <aside>Sidebar</aside>
      <main>{children}</main>
    </div>
  );
}

Mistake 2: Expecting State to Persist in Templates

TYPESCRIPT
// ❌ Won't work: State resets on navigation
// app/template.tsx
export default function Template({ children }) {
  const [user, setUser] = useState(null);
  
  // User will be lost on every navigation!
  return <>{children}</>;
}

// ✅ Use layout for persistent state
// app/layout.tsx
export default function Layout({ children }) {
  const [user, setUser] = useState(null);
  
  // User persists across navigation
  return <>{children}</>;
}

Mistake 3: Not Understanding the Performance Impact

Templates re-render on every navigation, which means re-running all component logic, effects, and re-mounting DOM elements. This has a performance cost that's usually unnecessary.

Decision Flowchart

Question:
Does your UI need to persist across page navigation?
↓ YES
Use layout.tsx

State persists, better performance, default choice

↓ NO
Do you specifically need re-rendering?

(animations, analytics, state reset)

↓ YES
Use template.tsx

Re-renders on every navigation

↓ NO
Use layout.tsx anyway

Default to layouts

Interactive Example

Template Example with Render Counting

See how templates re-render on every navigation

template.tsx

Output Preview

Click "Run Code" to see the output

Key Takeaways

  • Layouts persist - state maintained across navigation
  • Templates re-render - state resets on every navigation
  • Default to layouts - use templates only when needed
  • Templates have performance cost - re-mounting is expensive
  • Can use both together - Layout wraps Template wraps Children
  • Templates for: animations, analytics, state reset
  • Layouts for: persistent UI, shared state, performance
  • Document template usage - explain why it's needed

What's Next?

You now understand the subtle but important difference between layouts and templates! Next, we'll explore loading states with loading.tsx files. You'll learn how to create instant loading UI, use React Suspense boundaries automatically, and build skeleton screens that make your app feel incredibly fast.

Loading states are crucial for good UX—they show users that something is happening and prevent jarring blank screens. Let's master them!

🎯 When in Doubt

If you're unsure whether to use a layout or template, choose layout. It's the right choice 95% of the time. Only use templates when you have a specific, documented reason for needing re-rendering behavior.

Test Your Understanding

Question 1 of 4

What is the key difference between layouts and templates?

Master the difference between templates and layouts in Next.js! Learn when to use each for optimal behavior.

Previous
Nested Layouts
Next
Loading States with loading.tsx

Master Next.js Layouts & Loading States

Join 2,000+ developers building production Next.js apps. Get the next lesson on loading states delivered to your inbox - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

NextJS Tutorials

0 of 70 completed

Your Progress0%

Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo