Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Use Router Hook
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

useRouter Hook for Programmatic Navigation

Navigate with code in response to events and user actions

While Link components handle declarative navigation (clicking links), sometimes you need to navigate programmatically in response to events—form submissions, button clicks, API responses, or timers. The useRouter hook gives you full control over navigation in Client Components. You can push new pages, replace history entries, go back/forward, refresh data, and prefetch routes programmatically. Let's master programmatic navigation!

Basic useRouter Usage

Import useRouter from next/navigation and use it in Client Components:

components/NavigationButton.tsx
'use client';

import { useRouter } from 'next/navigation';

export function NavigationButton() {
  const router = useRouter();

  const handleClick = () => {
    // Navigate to /about
    router.push('/about');
  };

  return (
    <button 
      onClick={handleClick}
      className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
    >
      Go to About
    </button>
  );
}

// ✅ 'use client' directive required
// ✅ Import from 'next/navigation' (not 'next/router')
// ✅ Call router.push() to navigate
// ✅ Works in response to any event

⚠️ Client Components Only

useRouter only works in Client Components. For Server Components, use the redirect() function instead.

TYPESCRIPT
// Server Component
import { redirect } from 'next/navigation';

async function ServerPage() {
  const user = await getUser();
  
  if (!user) {
    redirect('/login'); // Use redirect() in Server Components
  }
  
  return <div>Welcome!</div>;
}

Router Methods

1. router.push() - Navigate with History

Add a new entry to the browser history:

TYPESCRIPT
'use client';

import { useRouter } from 'next/navigation';

export function NavigationExample() {
  const router = useRouter();

  return (
    <div className="space-y-4">
      {/* Navigate to different pages */}
      <button onClick={() => router.push('/blog')}>
        Go to Blog
      </button>

      <button onClick={() => router.push('/about')}>
        Go to About
      </button>

      {/* Navigate with query parameters */}
      <button onClick={() => router.push('/search?q=nextjs')}>
        Search for Next.js
      </button>

      {/* Navigate to dynamic route */}
      <button onClick={() => router.push(`/blog/${postId}`)}>
        View Post
      </button>
    </div>
  );
}

// ✅ Adds to browser history
// ✅ User can use back button
// ✅ Supports query parameters
// ✅ Works with dynamic routes

2. router.replace() - Replace History Entry

Replace the current history entry (user can't go back):

TYPESCRIPT
'use client';

import { useRouter } from 'next/navigation';

export function LoginForm() {
  const router = useRouter();

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    
    // Login logic
    const success = await login(email, password);
    
    if (success) {
      // Replace login page with dashboard
      // User can't go back to login page
      router.replace('/dashboard');
    }
  };

  return (
    <form onSubmit={handleLogin}>
      {/* Form fields */}
      <button type="submit">Login</button>
    </form>
  );
}

// Use router.replace() for:
// ✅ Post-login redirects
// ✅ Form submission redirects
// ✅ Intermediate/temporary pages
// ✅ When back button shouldn't work

// ❌ Don't use for normal navigation
// User expects back button to work

3. router.back() - Go Back

TYPESCRIPT
'use client';

import { useRouter } from 'next/navigation';

export function BackButton() {
  const router = useRouter();

  return (
    <button 
      onClick={() => router.back()}
      className="flex items-center gap-2 text-gray-600 hover:text-gray-900"
    >
      <span>←</span>
      Back
    </button>
  );
}

// ✅ Navigates to previous page in history
// ✅ Same as browser back button
// ✅ Useful for modal close, cancel actions

4. router.forward() - Go Forward

TYPESCRIPT
'use client';

import { useRouter } from 'next/navigation';

export function HistoryButtons() {
  const router = useRouter();

  return (
    <div className="flex gap-2">
      <button onClick={() => router.back()}>
        ← Back
      </button>
      
      <button onClick={() => router.forward()}>
        Forward →
      </button>
    </div>
  );
}

// ✅ Navigates to next page in history
// ✅ Same as browser forward button
// ✅ Only works if user went back first

5. router.refresh() - Refresh Data

Re-fetch Server Component data without losing client state:

TYPESCRIPT
'use client';

import { useRouter } from 'next/navigation';

export function RefreshButton() {
  const router = useRouter();

  const handleRefresh = () => {
    // Re-fetch server data for current route
    // Preserves client state (form inputs, scroll position)
    router.refresh();
  };

  return (
    <button 
      onClick={handleRefresh}
      className="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300"
    >
      🔄 Refresh
    </button>
  );
}

// When to use router.refresh():
// ✅ After creating/updating/deleting data
// ✅ After form submission
// ✅ Manual refresh button
// ✅ Polling for updates

// Example: After creating a post
const handleSubmit = async () => {
  await createPost(data);
  router.refresh(); // Show new post in list
};

// ✅ No full page reload
// ✅ Preserves client state
// ✅ Re-fetches Server Component data

6. router.prefetch() - Prefetch Route

TYPESCRIPT
'use client';

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

export function PrefetchExample() {
  const router = useRouter();

  useEffect(() => {
    // Prefetch dashboard when component mounts
    router.prefetch('/dashboard');
  }, [router]);

  return (
    <button onClick={() => router.push('/dashboard')}>
      Go to Dashboard (Prefetched)
    </button>
  );
}

// ✅ Manually prefetch routes
// ✅ Useful for conditional prefetching
// ✅ Route loads instantly when clicked

// Example: Prefetch on hover
const handleMouseEnter = () => {
  router.prefetch('/dashboard');
};

<button 
  onMouseEnter={handleMouseEnter}
  onClick={() => router.push('/dashboard')}
>
  Dashboard
</button>

Practical Examples

Example 1: Login Form with Redirect

components/LoginForm.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export function LoginForm() {
  const router = useRouter();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError('');

    try {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      });

      const data = await response.json();

      if (response.ok) {
        // Login successful - redirect to dashboard
        // Use replace so user can't go back to login page
        router.replace('/dashboard');
      } else {
        setError(data.message || 'Login failed');
      }
    } catch (err) {
      setError('An error occurred. Please try again.');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="max-w-md mx-auto space-y-4">
      <h2 className="text-2xl font-bold mb-6">Login</h2>

      {error && (
        <div className="bg-red-50 border border-red-200 text-red-800 px-4 py-3 rounded">
          {error}
        </div>
      )}

      <div>
        <label className="block text-sm font-medium mb-2">
          Email
        </label>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
          className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
        />
      </div>

      <div>
        <label className="block text-sm font-medium mb-2">
          Password
        </label>
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
          className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
        />
      </div>

      <button
        type="submit"
        disabled={loading}
        className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400"
      >
        {loading ? 'Logging in...' : 'Login'}
      </button>
    </form>
  );
}

// ✅ Form submission triggers navigation
// ✅ Uses router.replace() to prevent back to login
// ✅ Handles loading and error states
// ✅ Professional user experience

Example 2: Search Bar with Navigation

components/SearchBar.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export function SearchBar() {
  const router = useRouter();
  const [query, setQuery] = useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    
    if (query.trim()) {
      // Navigate to search results page with query
      router.push(`/search?q=${encodeURIComponent(query)}`);
    }
  };

  const handleClear = () => {
    setQuery('');
    // Go back to current page without query
    router.push(window.location.pathname);
  };

  return (
    <form onSubmit={handleSubmit} className="relative max-w-lg">
      <input
        type="search"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
        className="w-full px-4 py-2 pr-24 border rounded-lg focus:ring-2 focus:ring-blue-500"
      />
      
      <div className="absolute right-2 top-1/2 -translate-y-1/2 flex gap-2">
        {query && (
          <button
            type="button"
            onClick={handleClear}
            className="text-gray-500 hover:text-gray-700"
          >
            ✕
          </button>
        )}
        
        <button
          type="submit"
          className="px-4 py-1 bg-blue-600 text-white rounded hover:bg-blue-700"
        >
          Search
        </button>
      </div>
    </form>
  );
}

// ✅ Form submission navigates to search results
// ✅ Query parameter in URL
// ✅ Clear button removes query
// ✅ URL encoding for special characters

Example 3: Multi-Step Form with Navigation

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

import { useRouter } from 'next/navigation';
import { useState } from 'react';

type Step = 'shipping' | 'payment' | 'confirmation';

export default function CheckoutPage() {
  const router = useRouter();
  const [step, setStep] = useState<Step>('shipping');
  const [formData, setFormData] = useState({
    name: '',
    address: '',
    cardNumber: '',
  });

  const handleNext = () => {
    if (step === 'shipping') {
      setStep('payment');
    } else if (step === 'payment') {
      setStep('confirmation');
    }
  };

  const handleBack = () => {
    if (step === 'payment') {
      setStep('shipping');
    } else if (step === 'confirmation') {
      setStep('payment');
    }
  };

  const handleComplete = async () => {
    // Process order
    await submitOrder(formData);
    
    // Replace checkout with success page
    // User can't go back to checkout
    router.replace('/order/success');
  };

  return (
    <div className="container mx-auto px-4 py-8 max-w-2xl">
      <h1 className="text-3xl font-bold mb-8">Checkout</h1>

      {/* Progress Indicator */}
      <div className="flex justify-between mb-8">
        <div className={`flex-1 text-center ${step === 'shipping' ? 'text-blue-600 font-bold' : 'text-gray-400'}`}>
          1. Shipping
        </div>
        <div className={`flex-1 text-center ${step === 'payment' ? 'text-blue-600 font-bold' : 'text-gray-400'}`}>
          2. Payment
        </div>
        <div className={`flex-1 text-center ${step === 'confirmation' ? 'text-blue-600 font-bold' : 'text-gray-400'}`}>
          3. Confirm
        </div>
      </div>

      {/* Step Content */}
      {step === 'shipping' && (
        <div className="space-y-4">
          <h2 className="text-2xl font-bold mb-4">Shipping Information</h2>
          <input
            type="text"
            placeholder="Full Name"
            value={formData.name}
            onChange={(e) => setFormData({ ...formData, name: e.target.value })}
            className="w-full px-4 py-2 border rounded-lg"
          />
          <input
            type="text"
            placeholder="Address"
            value={formData.address}
            onChange={(e) => setFormData({ ...formData, address: e.target.value })}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
      )}

      {step === 'payment' && (
        <div className="space-y-4">
          <h2 className="text-2xl font-bold mb-4">Payment Information</h2>
          <input
            type="text"
            placeholder="Card Number"
            value={formData.cardNumber}
            onChange={(e) => setFormData({ ...formData, cardNumber: e.target.value })}
            className="w-full px-4 py-2 border rounded-lg"
          />
        </div>
      )}

      {step === 'confirmation' && (
        <div className="space-y-4">
          <h2 className="text-2xl font-bold mb-4">Confirm Order</h2>
          <div className="bg-gray-50 p-4 rounded-lg space-y-2">
            <p><strong>Name:</strong> {formData.name}</p>
            <p><strong>Address:</strong> {formData.address}</p>
            <p><strong>Card:</strong> **** **** **** {formData.cardNumber.slice(-4)}</p>
          </div>
        </div>
      )}

      {/* Navigation Buttons */}
      <div className="flex justify-between mt-8">
        <button
          onClick={step === 'shipping' ? () => router.back() : handleBack}
          className="px-6 py-3 border rounded-lg hover:bg-gray-50"
        >
          {step === 'shipping' ? 'Cancel' : 'Back'}
        </button>

        {step === 'confirmation' ? (
          <button
            onClick={handleComplete}
            className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700"
          >
            Complete Order
          </button>
        ) : (
          <button
            onClick={handleNext}
            className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
          >
            Next
          </button>
        )}
      </div>
    </div>
  );
}

// ✅ Multi-step form with state
// ✅ Back/Next navigation
// ✅ router.replace() on completion
// ✅ Can't go back after order complete

Example 4: Conditional Navigation After API Call

components/CreatePostButton.tsx
'use client';

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export function CreatePostButton({ userId }: { userId: string }) {
  const router = useRouter();
  const [loading, setLoading] = useState(false);

  const handleCreatePost = async () => {
    setLoading(true);

    try {
      const response = await fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          userId,
          title: 'New Post',
          content: 'Draft content',
        }),
      });

      const data = await response.json();

      if (response.ok) {
        // Navigate to the newly created post for editing
        router.push(`/blog/edit/${data.slug}`);
        
        // Refresh the blog list in background
        router.refresh();
      } else {
        alert('Failed to create post');
      }
    } catch (error) {
      alert('An error occurred');
    } finally {
      setLoading(false);
    }
  };

  return (
    <button
      onClick={handleCreatePost}
      disabled={loading}
      className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400"
    >
      {loading ? 'Creating...' : 'Create New Post'}
    </button>
  );
}

// ✅ API call then navigation
// ✅ Navigate to new resource
// ✅ Refresh to show changes
// ✅ Loading state during API call

useRouter Examples Structure

Project structure with useRouter usage patterns

appImportant

Select a file or folder to see details

Common Navigation Patterns

Pattern 1: Navigate After Successful Action

TYPESCRIPT
const handleSubmit = async () => {
  const success = await saveData(data);
  
  if (success) {
    router.push('/success');
  } else {
    // Show error, stay on page
  }
};

Pattern 2: Navigate with Confirmation

TYPESCRIPT
const handleDelete = async () => {
  if (confirm('Are you sure you want to delete this?')) {
    await deleteItem(id);
    router.push('/items'); // Go back to list
    router.refresh(); // Refresh the list
  }
};

Pattern 3: Timed Redirect

TYPESCRIPT
useEffect(() => {
  // Redirect after 3 seconds
  const timer = setTimeout(() => {
    router.push('/home');
  }, 3000);

  return () => clearTimeout(timer);
}, [router]);

Pattern 4: Conditional Redirect on Mount

TYPESCRIPT
useEffect(() => {
  // Check authentication
  const checkAuth = async () => {
    const user = await getUser();
    
    if (!user) {
      router.replace('/login');
    }
  };

  checkAuth();
}, [router]);

useRouter Best Practices

1. Use router.replace() for One-Way Flows

TYPESCRIPT
// ✅ GOOD: Replace for login redirects
const handleLogin = async () => {
  await login();
  router.replace('/dashboard'); // Can't go back to login
};

// ❌ BAD: Push for login (user can go back)
const handleLogin = async () => {
  await login();
  router.push('/dashboard'); // User can press back to login
};

2. Handle Loading States

TYPESCRIPT
// ✅ GOOD: Show loading during navigation
const [loading, setLoading] = useState(false);

const handleClick = async () => {
  setLoading(true);
  await saveData();
  router.push('/success');
  // Note: Component might unmount, so no setLoading(false)
};

return (
  <button disabled={loading}>
    {loading ? 'Saving...' : 'Save'}
  </button>
);

3. Use router.refresh() After Mutations

TYPESCRIPT
// ✅ GOOD: Refresh after creating/updating/deleting
const handleCreate = async () => {
  await createPost(data);
  router.refresh(); // Show new post in list
};

const handleUpdate = async () => {
  await updatePost(id, data);
  router.refresh(); // Show updated data
};

const handleDelete = async () => {
  await deletePost(id);
  router.push('/blog'); // Go to list
  router.refresh(); // Update the list
};

4. Don't Navigate in Render

TYPESCRIPT
// ❌ BAD: Navigating during render
function MyComponent() {
  const router = useRouter();
  
  if (condition) {
    router.push('/other'); // Don't do this!
  }
  
  return <div>Content</div>;
}

// ✅ GOOD: Navigate in effect or event handler
function MyComponent() {
  const router = useRouter();
  
  useEffect(() => {
    if (condition) {
      router.push('/other');
    }
  }, [condition, router]);
  
  return <div>Content</div>;
}

5. Clean Up Timers

TYPESCRIPT
// ✅ GOOD: Clean up timers on unmount
useEffect(() => {
  const timer = setTimeout(() => {
    router.push('/home');
  }, 3000);

  return () => clearTimeout(timer); // Clean up
}, [router]);

Key Takeaways

  • Client Components only - needs 'use client' directive
  • Import from 'next/navigation' - not 'next/router'
  • router.push() - navigate with history (can go back)
  • router.replace() - replace history (can't go back)
  • router.back()/forward() - browser history navigation
  • router.refresh() - re-fetch data without reload
  • Use for event handlers - form submits, button clicks
  • Handle loading states - show feedback during navigation

What's Next?

You've mastered programmatic navigation with useRouter! Next, we'll explore usePathname and useSearchParams Hooks—how to access the current pathname and search parameters in Client Components. You'll learn to read the current URL, work with query parameters, and build navigation UI that responds to the current route.

These hooks are essential for active link highlighting, reading filters from the URL, conditional rendering based on the current route, and more.

🎯 When to Use Each Method

Use router.push() for most navigation. Use router.replace() only when you specifically don't want users to go back. Think of replace as "this page shouldn't exist in history."

Test Your Understanding

Question 1 of 4

Where can you use the useRouter hook?

Master programmatic navigation in Next.js with the useRouter hook! Learn push, replace, refresh, and more.

Previous
Link Component Basics
Next
usePathname and useSearchParams Hooks

Master Next.js Navigation Hooks

Join 2,000+ developers building dynamic Next.js apps. Get the next lesson on usePathname and useSearchParams - 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