BasicsVSCodeNext.jsStyled ComponentsSetupProjectsResourcesIndex
Template Hero

Template Guide

A Next.js Starter with Styled Components

Project Setup

Open VSCode and Terminal

Purpose:

Start your setup by preparing your development environment.

Use Case:

Ensure you’re ready to execute commands within VSCode.

Example:
  • Launch Visual Studio Code.
  • Open the integrated terminal in VSCode: View > Terminal or press Cmd + J.
Pro Tip:

Use VSCode’s terminal to keep all your work in one place.

Create a New Next.js Project

Purpose:

Initialize a Next.js project with TypeScript and the App Router.

Use Case:

Set up the foundation for your Styled Components template.

Example:
  • In the VSCode terminal, navigate to your desired directory (e.g., cd ~/projects).
  • Run this command:
    npx create-next-app@latest next-styled-template --typescript --eslint --app --src-dir --no-tailwind --no-experimental-app
  • Prompts:
    • Project name: next-styled-template (or press Enter if pre-filled).
    • TypeScript: Yes.
    • ESLint: Yes.
    • Tailwind CSS: No (we’ll use Styled Components).
    • src/ directory: Yes.
    • App Router: Yes.
    • Customize import alias: No.
Pro Tip:

The --src-dir flag organizes your code neatly.

Navigate to Project Directory

Purpose:

Move into your new project folder to begin setup.

Use Case:

Prepare to open and configure your project.

Example:
  • In the VSCode terminal, run:
    cd next-styled-template
Pro Tip:

Keep your terminal in the project root for all commands.

Enable VSCode CLI

Purpose:

Ensure the code command works in your VSCode terminal.

Use Case:

Open your project seamlessly within VSCode.

Example:
  • If code . fails with "command not found":
    • Open the Command Palette in VSCode: Cmd + Shift + P (Mac) or Ctrl + Shift + P (Windows/Linux).
    • Type and select: "Shell Command: Install 'code' command in PATH".
    • Run this in your terminal to confirm:
      code --version
    • You should see the VSCode version (e.g., "1.93.1"). If not, restart your terminal or VSCode.
Pro Tip:

This step is needed only once per machine to enable the code command.

Open Project in VSCode

Purpose:

Open your project in VSCode for editing.

Use Case:

Access your project files within the VSCode editor.

Example:
  • In the VSCode terminal, run:
    code .
  • This opens the next-styled-template folder in your current VSCode window.
Pro Tip:

Use code -r . to reuse the current VSCode window if another is open.

Install Dependencies

Purpose:

Add Styled Components and other required packages.

Use Case:

Enable the features used in this template.

Example:
  • In the VSCode terminal, run:
    • Install Styled Components and types:
      npm install styled-components @types/styled-components
    • Install additional dependencies for this template:
      npm install react-markdown remark-gfm react-syntax-highlighter
Pro Tip:

Check package.json after installation to verify versions.

Update Next.js Configuration

Purpose:

Configure Next.js to support Styled Components.

Use Case:

Ensure proper SSR and styling functionality.

Example:
  • Open next.config.ts in VSCode and replace its contents with:
    // next.config.ts
    /** @type {import('next').NextConfig} */
    const nextConfig = {
      compiler: {
        styledComponents: true,
      },
    };
    
    export default nextConfig;
Pro Tip:

This enables Styled Components’ SSR capabilities.

Understand the Initial File Structure

Purpose:

Familiarize yourself with the project’s starting layout.

Use Case:

Know where to place files as you build the template.

Example:

After setup, your project structure looks like this:

next-styled-template/
├── node_modules/
├── public/
│   ├── favicon.ico
│   ├── next.svg
│   └── vercel.svg
├── src/
│   ├── app/
│   │   ├── layout.tsx
│   │   ├── page.tsx
│   │   ├── globals.css
│   │   └── favicon.ico
│   └── components/
├── .eslintrc.json
├── .gitignore
├── next-env.d.ts
├── next.config.ts
├── package.json
├── README.md
├── tsconfig.json
Pro Tip:

Use VSCode’s file explorer to visualize this structure.

Add Styled Components Support Files

Purpose:

Set up theme, styles, and SSR support for Styled Components.

Use Case:

Prepare reusable styling and ensure SSR compatibility.

Example:
  • Theme File: Create src/lib/theme.ts:
    // src/lib/theme.ts
    export const theme = {
      colors: {
        primary: "#0070f3",
        textDark: "#ffffff",
        textLight: "#a0aec0",
        backgroundContent: "#2d3748",
        backgroundLight: "#4a5568",
        backgroundDark: "#1a202c",
      },
    };
  • Styles File: Create src/lib/styles.ts:
    // src/lib/styles.ts
    import styled from "styled-components";
    import Image from "next/image";
    
    export const PageContainer = styled.div`
      min-height: 100vh;
      display: flex;
      flex-direction: column;
    `;
    
    export const HeroContainer = styled.div`
      position: relative;
      height: 50vh;
      width: 100%;
    `;
    
    export const HeroImage = styled(Image)`
      object-fit: cover;
      width: 100%;
      height: 100%;
    `;
    
    export const HeroText = styled.div`
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      color: white;
    `;
    
    export const HeroTitle = styled.h1`
      font-size: 3rem;
      margin: 0;
    `;
    
    export const HeroSubtitle = styled.h2`
      font-size: 1.5rem;
      margin: 0;
    `;
    
    export const ContentContainer = styled.div`
      padding: 2rem;
      max-width: 1200px;
      margin: 0 auto;
    `;
    
    export const Container = styled.div`
      width: 100%;
      max-width: 1200px;
      margin: 0 auto;
      padding: 0 1rem;
    `;
  • Custom Document (Optional): Create src/app/_document.tsx:
    // src/app/_document.tsx
    import Document, { Html, Head, Main, NextScript } from "next/document";
    
    class MyDocument extends Document {
      render() {
        return (
          <Html lang="en">
            <Head />
            <body>
              <Main />
              <NextScript />
            </body>
          </Html>
        );
      }
    }
    
    export default MyDocument;
  • Styled Components Registry: Create src/components/styled-components-registry.tsx:
    // src/components/styled-components-registry.tsx
    "use client";
    
    import React, { useState } from "react";
    import { useServerInsertedHTML } from "next/navigation";
    import { ServerStyleSheet, StyleSheetManager } from "styled-components";
    
    export default function StyledComponentsRegistry({
      children,
    }: {
      children: React.ReactNode;
    }) {
      const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet());
    
      useServerInsertedHTML(() => {
        const styles = styledComponentsStyleSheet.getStyleElement();
        styledComponentsStyleSheet.instance.clearTag();
        return <>{styles}</>;
      });
    
      if (typeof window !== "undefined") return <>{children}</>;
    
      return (
        <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
          {children}
        </StyleSheetManager>
      );
    }
  • Theme Wrapper: Create src/components/ThemeWrapper.tsx:
    // src/components/ThemeWrapper.tsx
    "use client";
    
    import { ThemeProvider } from "styled-components";
    import { theme } from "../lib/theme"; // Adjust to src/lib/theme after setup
    import { ReactNode } from "react";
    
    interface ThemeWrapperProps {
      children: ReactNode;
    }
    
    export default function ThemeWrapper({ children }: ThemeWrapperProps) {
      return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
    }
Pro Tip:

Place reusable utilities in src/lib/ and client components in src/components/.

Customize the Initial Page

Purpose:

Enhance the default homepage with a professional look using Styled Components.

Use Case:

Create an inviting entry point for your application.

Example:
  • Replace src/app/page.tsx with this polished version:
    // src/app/page.tsx
    "use client";
    
    import { useState } from "react";
    import styled from "styled-components";
    import { Container } from "../lib/styles"; // Adjust to src/lib/styles after setup
    import { theme } from "../lib/theme"; // Adjust to src/lib/theme after setup
    
    const WelcomeCard = styled.div`
      background: ${theme.colors.textDark};
      border-radius: 12px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
      padding: 2rem;
      max-width: 600px;
      margin: 2rem auto;
      transition: transform 0.3s ease;
      &:hover {
        transform: translateY(-5px);
      }
    `;
    
    const Title = styled.h1`
      font-size: 2.5rem;
      font-weight: 700;
      color: ${theme.colors.backgroundDark};
      margin: 0 0 1rem;
    `;
    
    const Text = styled.p`
      font-size: 1.125rem;
      color: ${theme.colors.backgroundLight};
      line-height: 1.6;
      margin: 0 0 1.5rem;
    `;
    
    const Button = styled.button`
      background: ${theme.colors.primary};
      color: ${theme.colors.textDark};
      border: none;
      padding: 0.75rem 1.5rem;
      font-size: 1rem;
      font-weight: 600;
      border-radius: 8px;
      cursor: pointer;
      transition: background 0.3s ease;
      &:hover {
        background: ${theme.colors.backgroundDark};
      }
    `;
    
    const Progress = styled.div<{ active: boolean }>`
      height: 4px;
      background: ${theme.colors.textLight};
      border-radius: 2px;
      overflow: hidden;
      margin-top: 1rem;
      &::after {
        content: "";
        display: block;
        width: 50%;
        height: 100%;
        background: ${theme.colors.primary};
        transform: translateX(${({ active }) => (active ? "100%" : "0")});
        transition: transform 0.5s ease;
      }
    `;
    
    export default function Home() {
      const [isExploring, setIsExploring] = useState(false);
    
      return (
        <Container>
          <WelcomeCard>
            <Title>Welcome to Your Next.js Journey</Title>
            <Text>
              This template provides a sleek foundation with Styled Components and
              the App Router. Click below to start exploring and building your app!
            </Text>
            <Button onClick={() => setIsExploring(!isExploring)}>
              {isExploring ? "Pause Exploration" : "Start Exploring"}
            </Button>
            <Progress active={isExploring} />
          </WelcomeCard>
        </Container>
      );
    }
Pro Tip:

Use Styled Components to maintain a consistent look across your app.

Test Your Project

Purpose:

Verify your setup and initial page are working correctly.

Use Case:

Ensure a smooth start before adding more features.

Example:
  • In the VSCode terminal, run:
    npm run dev
  • Open your browser to http://localhost:3000 to see your new homepage.
  • Navigate to http://localhost:3000/template after adding the guide content (next steps).
Pro Tip:

Use VSCode’s built-in browser preview for quick testing.

Next.js Template Essentials

Getting Started

Purpose:

Set up a basic Next.js page with Styled Components to kick off your project.

Use Case:

Use this as your starting point for any Next.js application with a clean, styled layout.

Example:

Getting Started

// app/page.tsx
"use client";

import styled from "styled-components";
import Link from "next/link";

const PageContainer = styled.div`
  display: grid;
  grid-template-rows: 1fr auto; /* Main content and footer */
  min-height: 100vh;
  width: 100%; /* Full viewport width */
  background: #F7F4E9; /* Soft beige background */
  padding: 2rem 0; /* Vertical padding only */
`;

const MainContent = styled.main`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
  text-align: center;
  padding: 2rem 1rem; /* Minimal horizontal padding for content */

  @media (max-width: 768px) {
    padding: 1.5rem 1rem;
    gap: 1.5rem;
  }

  @media (max-width: 480px) {
    padding: 1rem;
    gap: 1rem;
  }
`;

const HeroTitle = styled.h1`
  font-size: 3.5rem;
  font-weight: 700;
  color: #000000; /* Black for title */
  margin: 0;
  line-height: 1.2;

  @media (max-width: 768px) {
    font-size: 2.5rem;
  }

  @media (max-width: 480px) {
    font-size: 2rem;
  }
`;

const HeroSubtitle = styled.p`
  font-size: 1.25rem;
  color: #333333; /* Dark gray for subtitle */
  max-width: 600px;
  line-height: 1.6;
  margin: 0;

  @media (max-width: 768px) {
    font-size: 1.1rem;
    max-width: 500px;
  }

  @media (max-width: 480px) {
    font-size: 1rem;
    max-width: 300px;
  }
`;

const ButtonContainer = styled.div`
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 2rem;

  @media (max-width: 768px) {
    gap: 1rem;
    margin-top: 1.5rem;
  }

  @media (max-width: 480px) {
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1rem;
  }
`;

const ActionButton = styled(Link)`
  padding: 0.75rem 1.5rem;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  border-radius: 8px;
  background: #000000; /* Black for buttons */
  color: #FFFFFF; /* White text */
  transition: background 0.3s ease;
  cursor: pointer;

  &:hover {
    background: #333333; /* Dark gray on hover */
  }

  @media (max-width: 768px) {
    padding: 0.6rem 1.2rem;
    font-size: 0.9rem;
  }

  @media (max-width: 480px) {
    padding: 0.5rem 1rem;
    width: 100%;
    max-width: 200px;
  }
`;

const Footer = styled.footer`
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
  justify-content: center;
  padding: 1rem;
  color: #333333; /* Dark gray for footer */

  @media (max-width: 768px) {
    gap: 1rem;
    padding: 0.75rem;
  }

  @media (max-width: 480px) {
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem;
  }
`;

const FooterLink = styled.a`
  color: #333333; /* Dark gray for links */
  text-decoration: none;
  font-size: 0.9rem;
  transition: color 0.3s ease;

  &:hover {
    color: #000000; /* Black on hover */
  }

  @media (max-width: 768px) {
    font-size: 0.85rem;
  }

  @media (max-width: 480px) {
    font-size: 0.8rem;
    width: 100%;
    text-align: center;
  }
`;

export default function Home() {
  return (
    <PageContainer>
      <MainContent>
        <HeroTitle>Welcome</HeroTitle>
        <HeroSubtitle>
          Kickstart your Next.js journey with this sleek template featuring Styled Components and the App Router.
        </HeroSubtitle>
        <ButtonContainer>
          <ActionButton href="/template">Explore Guide</ActionButton>
          <ActionButton href="https://nextjs.org/docs" target="_blank" rel="noopener noreferrer">
            Next.js Docs
          </ActionButton>
        </ButtonContainer>
      </MainContent>
      <Footer>
        <FooterLink href="https://github.com" target="_blank" rel="noopener noreferrer">
          GitHub
        </FooterLink>
        <FooterLink href="https://nextjs.org" target="_blank" rel="noopener noreferrer">
          Next.js
        </FooterLink>
        <FooterLink href="https://styled-components.com" target="_blank" rel="noopener noreferrer">
          Styled Components
        </FooterLink>
      </Footer>
    </PageContainer>
  );
}

How It Works:

  • A fully responsive homepage with a flat, simplistic black-and-white design on a soft beige background (#F7F4E9).
  • Spans edge-to-edge with no side gaps using full viewport width.
  • Features a bold black title, dark gray subtitle, and black buttons with white text for a clean, minimal look.
  • Buttons and footer links adapt to screen size, maintaining usability without excessive colors or effects.
Pro Tip:

Keep your initial page simple to build momentum—add complexity as needed.

Core Structure

The core files include a minimal layout, a toolbar for navigation, and this guide page. These provide the foundation for your Next.js app with App Router support.

Root Layout

Purpose:

Define the basic HTML structure and include a toolbar for all pages.

Use Case:

Use this to set up global styles and navigation across your app.

Example:

Root Layout Example

// app/layout.tsx
import { ReactNode } from "react";
import StyledComponentsRegistry from "../components/styled-components-registry"; // Adjust to src/components/ after setup
import Toolbar from "../components/Toolbar"; // Adjust to src/components/Toolbar after setup
import ThemeWrapper from "../components/ThemeWrapper"; // Adjust to src/components/ThemeWrapper after setup
import { CSSProperties } from "react";

export const metadata = {
  title: "Next.js Styled Template",
  description: "A Next.js starter with Styled Components",
};

// Define inline styles with TypeScript typing for server compatibility
const heroStyle: CSSProperties = {
  background: "#1a202c", // Hardcoded theme.colors.backgroundDark
  padding: "4rem 2rem",
  textAlign: "center",
};

const heroTitleStyle: CSSProperties = {
  fontSize: "3rem",
  fontWeight: 700,
  color: "#f5f5d5", // Beige color
  margin: 0,
};

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <StyledComponentsRegistry>
          <ThemeWrapper>
            <Toolbar />
            {children}
          </ThemeWrapper>
        </StyledComponentsRegistry>
      </body>
    </html>
  );
}

How It Works:

  • A server component with a minimal hero section using typed inline styles.
  • Wraps content in a client-side ThemeWrapper for Styled Components compatibility.
  • Includes the toolbar and page content below the hero.
  • Hardcodes theme colors since theme can't be imported server-side here.
Pro Tip:

Keep global styles minimal in layout.tsx and let pages handle specific styling.

Toolbar

Purpose:

Provide a simple navigation bar with a toggleable menu for your app.

Use Case:

Ideal for adding consistent navigation without much overhead.

Example:

Toolbar Example

// src/components/Toolbar.tsx
"use client";

import { useState } from "react";
import styled from "styled-components";
import Link from "next/link";
import { theme } from "../lib/theme"; 

const ToolbarContainer = styled.nav`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background-color: ${theme.colors.backgroundDark};
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 1000;
  box-sizing: border-box;
  min-height: 60px;
`;

const Logo = styled(Link)`
  font-size: 1.75rem;
  font-weight: 700;
  color: ${theme.colors.textDark};
  text-decoration: none;
  transition: color 0.3s ease;
  &:hover {
    color: ${theme.colors.textLight};
  }
`;

const NavLinks = styled.div`
  display: flex;
  gap: 1.5rem;
  align-items: center;

  @media (max-width: 768px) {
    display: none; /* Hide tabs on smaller screens */
  }
`;

const NavLink = styled(Link)`
  font-size: 1.1rem;
  font-weight: 500;
  color: ${theme.colors.textDark};
  text-decoration: none;
  transition: color 0.3s ease;
  &:hover {
    color: ${theme.colors.primary};
  }
`;

const BurgerIcon = styled.div<{ $isOpen: boolean }>`
  display: none; /* Hidden on larger screens */
  flex-direction: column;
  gap: 5px;
  cursor: pointer;
  padding: 0.5rem;

  @media (max-width: 768px) {
    display: flex; /* Show on smaller screens */
  }

  div {
    width: 25px;
    height: 3px;
    background-color: ${theme.colors.textDark};
    border-radius: 2px;
    transition: all 0.3s ease;
  }

  ${({ $isOpen }) =>
    $isOpen &&
    `
    div:nth-child(1) {
      transform: rotate(45deg) translate(5px, 5px);
    }
    div:nth-child(2) {
      opacity: 0;
    }
    div:nth-child(3) {
      transform: rotate(-45deg) translate(6px, -6px);
    }
  `}
`;

const MobileMenu = styled.div<{ $isOpen: boolean }>`
  display: ${({ $isOpen }) => ($isOpen ? "flex" : "none")};
  flex-direction: column;
  align-items: center;
  position: fixed;
  top: 60px;
  left: 0;
  width: 100%;
  background: ${theme.colors.backgroundContent};
  padding: 2rem 0;
  z-index: 999;
  transition: opacity 0.3s ease;

  @media (min-width: 769px) {
    display: none; /* Hide on larger screens */
  }
`;

const MobileNavLink = styled(Link)`
  font-size: 1.5rem;
  font-weight: 600;
  color: ${theme.colors.textDark};
  text-decoration: none;
  padding: 1rem;
  width: 100%;
  text-align: center;
  transition: color 0.3s ease;
  &:hover {
    color: ${theme.colors.primary};
  }
`;

export default function Toolbar() {
  const [isOpen, setIsOpen] = useState(false);

  const toggleMenu = () => {
    setIsOpen((prev) => !prev);
  };

  return (
    <>
      <ToolbarContainer>
        <Logo href="/">My App</Logo>
        <NavLinks>
          <NavLink href="/">Home</NavLink>
          <NavLink href="/template">Guide</NavLink>
        </NavLinks>
        <BurgerIcon $isOpen={isOpen} onClick={toggleMenu}>
          <div></div>
          <div></div>
          <div></div>
        </BurgerIcon>
      </ToolbarContainer>
      <MobileMenu $isOpen={isOpen}>
        <MobileNavLink href="/" onClick={toggleMenu}>
          Home
        </MobileNavLink>
        <MobileNavLink href="/template" onClick={toggleMenu}>
          Guide
        </MobileNavLink>
      </MobileMenu>
    </>
  );
}

How It Works:

  • A responsive toolbar with two tabs: "Home" and "Guide".
  • On larger screens (>768px), tabs display inline next to the logo.
  • On smaller screens (≤768px), tabs hide, and a burger icon toggles a mobile menu.
  • Uses theme colors for consistency: dark background, light text, and primary accents.
  • Smooth transitions for hover effects and menu toggle.
Pro Tip:

Customize the toolbar’s colors in theme.ts to match your brand.

Guide Page

Purpose:

Serve as the entry point to explore and learn about your template.

Use Case:

Use this page to document your project setup and showcase examples.

Example:

Template Page Example

// app/template/page.tsx
"use client";

import styled from "styled-components";

const PageWrapper = styled.div`
  padding: 80px 2rem 2rem;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
`;

const Heading = styled.h1`
  font-size: 2.5rem;
  font-weight: 700;
  color: #2d3748;
  margin-bottom: 1rem;
`;

const Description = styled.p`
  font-size: 1.25rem;
  color: #718096;
  line-height: 1.6;
`;

export default function TemplatePage() {
  return (
    <PageWrapper>
      <Heading>Welcome</Heading>
      <Description>
        This is a simple Next.js starter template built with Styled Components.
      </Description>
    </PageWrapper>
  );
}

How It Works:

  • Styled Components: Replaces inline styles with clean, reusable components.
  • Simple Design: Keeps layout minimal with centered text and subtle colors.
  • Professional Touch: Uses consistent typography and spacing for a polished look.
Pro Tip:

Keep this page updated as you add more features to your template.

Template Examples

These examples demonstrate common Next.js features with Styled Components, from routing to optimization, giving you a head start on typical use cases.

File-Based Routing

Purpose:

Showcase Next.js’s automatic routing based on file structure.

Use Case:

Use this for simple static pages like About or Contact.

Example:

File-Based Routing Example

Next.js uses file-based routing to create pages automatically based on the app/ directory structure. Here’s a simple example:

// app/page.tsx
"use client";

export default function Home() {
  return <h1>Home Page</h1>;
}

// app/about/page.tsx
"use client";

export default function About() {
  return <h1>About Page</h1>;
}

// app/contact/page.tsx
"use client";

export default function Contact() {
  return <h1>Contact Page</h1>;
}

How It Works:

  • app/page.tsx/ (root route)
  • app/about/page.tsx/about
  • app/contact/page.tsx/contact

Add files to app/ with a page.tsx to create new routes instantly.

Pro Tip:

Name files intuitively to reflect their route (e.g., about.tsx for /about).

Server-Side Rendering (SSR)

Purpose:

Render pages on the server for dynamic, SEO-friendly content.

Use Case:

Perfect for pages needing fresh data, like a dashboard or news feed.

Example:

Server-Side Rendering Example

// app/ssr/page.tsx
import { Container, Title, Text } from "../../lib/styles";

export default async function SSR() {
  // Fetches data on the server for each request
  const res = await fetch("https://api.example.com/data", {
    cache: "no-store", // Ensures fresh data per request
  });
  const data = await res.json();

  return (
    <Container>
      <Title>Server-Side Rendering</Title>
      <Text>
        Fetched on the server: {data.message || "Dynamic content here"}
      </Text>
    </Container>
  );
}

How It Works:

  • This is a server component (no "use client") that runs on the server.
  • fetch retrieves fresh data for each request, making it true SSR.
  • Place this at app/ssr/page.tsx to access it at /ssr.
Pro Tip:

Keep SSR logic lightweight to avoid performance bottlenecks.

Static Site Generation (SSG)

Purpose:

Pre-render pages at build time for fast, static content delivery.

Use Case:

Use this for blogs, docs, or landing pages that don’t change often.

Example:

Static Site Generation Example

// app/ssg/page.tsx
import { Container, Title, Text } from "../../lib/styles";

export default async function SSG() {
  // Fetches data at build time
  const res = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
    cache: "force-cache", // Ensures data is cached for static generation
  });
  const post = await res.json();

  return (
    <Container>
      <Title>Static Site Generation</Title>
      <Text>
        Pre-rendered at build time: {post.title || "Static content here"}
      </Text>
    </Container>
  );
}

// Optional: Incremental Static Regeneration (ISR)
export const revalidate = 3600; // Revalidate every hour

How It Works:

  • This is a server component that runs at build time to fetch and render static content.
  • fetch with cache: "force-cache" ensures data is fetched once during build.
  • Place this at app/ssg/page.tsx to access it at /ssg as a static page.
  • revalidate enables Incremental Static Regeneration (ISR) to update content periodically.
Pro Tip:

Add revalidate in getStaticProps for incremental static regeneration.

API Routes

Purpose:

Create simple API endpoints within your Next.js app.

Use Case:

Great for form submissions or fetching data without a separate backend.

Example:

API Routes Example

// app/api/hello/route.ts
import { NextResponse } from "next/server";

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const name = searchParams.get("name") || "World";

  return NextResponse.json({
    message: `Hello, ${name}!`,
    timestamp: new Date().toISOString(),
  });
}

How It Works:

  • This defines a server-side API endpoint at /api/hello.
  • The GET handler responds with JSON data, e.g., {"message": "Hello, World!", "timestamp": "2025-04-11T..."}).
  • Access it via fetch("/api/hello?name=User") or visit http://localhost:3000/api/hello locally.
  • Use it for lightweight tasks like form submissions or data fetching.
Pro Tip:

Test endpoints locally at http://localhost:3000/api/... during development.

Dynamic Routes

Purpose:

Handle variable URLs like /post/[id] with dynamic routing.

Use Case:

Use this for blog posts, product pages, or any parameterized content.

Example:

Dynamic Routes Example

// app/blog/[slug]/page.tsx
import { Container, Title, Text } from "../../../lib/styles";

export default async function BlogPost({ params }: { params: { slug: string } }) {
  // Fetch data based on the dynamic slug parameter
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.slug}`, {
    cache: "force-cache", // Static generation
  });
  const post = await res.json();

  return (
    <Container>
      <Title>{post.title || "Blog Post"}</Title>
      <Text>{post.body || "Post content not found"}</Text>
    </Container>
  );
}

// Pre-render specific slugs at build time
export async function generateStaticParams() {
  return [
    { slug: "1" },
    { slug: "2" },
    { slug: "3" },
  ];
}

How It Works:

  • Defines a dynamic route at /blog/[slug], e.g., /blog/1, /blog/2.
  • The [slug] parameter is passed via params.slug to fetch specific data.
  • generateStaticParams pre-renders pages for slugs "1", "2", "3" at build time.
  • Use fetch with cache: "force-cache" for static generation, or omit for SSR.
Pro Tip:

Combine with getStaticPaths for pre-rendered dynamic pages.

Image Optimization

Purpose:

Optimize images with Next.js’s <Image> component for better performance.

Use Case:

Ideal for image-heavy pages like galleries or portfolios.

Example:

Image Optimization Example

// app/gallery/page.tsx
import Image from "next/image";
import { Container, Title, Text } from "../../lib/styles";

export default function Gallery() {
  return (
    <Container>
      <Title>Image Gallery</Title>
      <Text>Optimized images load fast and responsively.</Text>
      <Image
        src="/images/sample.jpg" // Place image in /public/images/
        alt="Sample Image"
        width={600}
        height={400}
        priority // Loads immediately for above-the-fold content
      />
    </Container>
  );
}

How It Works:

  • The Image component from next/image optimizes images automatically.
  • width and height ensure proper aspect ratio and resizing.
  • priority preloads the image for better performance on key visuals.
  • Place static images in /public/ to serve them efficiently.
Pro Tip:

Set priority on above-the-fold images to load them first.

TypeScript Integration

Purpose:

Add type safety to your Next.js app with TypeScript.

Use Case:

Use this for larger projects or teams to catch errors early.

Example:

TypeScript Integration Example

// app/profile/page.tsx
import { Container, Title, Text } from "../../lib/styles";

// Define a TypeScript interface for props
interface UserProfile {
  name: string;
  email: string;
  role: "admin" | "user";
}

export default function Profile({ user }: { user: UserProfile }) {
  return (
    <Container>
      <Title>{user.name}’s Profile</Title>
      <Text>
        Email: {user.email} | Role: {user.role}
      </Text>
    </Container>
  );
}

// Example usage with static data (could be fetched)
export async function getServerSideProps() {
  const user: UserProfile = {
    name: "Jane Doe",
    email: "jane@example.com",
    role: "admin",
  };
  return { props: { user } };
}

How It Works:

  • The UserProfile interface enforces type safety for the user prop.
  • TypeScript catches errors if props don’t match (e.g., missing email).
  • Use this in larger projects for better code reliability and IntelliSense support.
Pro Tip:

Leverage VSCode’s IntelliSense with TypeScript for faster coding.

Chatbot

...

Welcome to the Prompted Chatbot! How can I assist you today?