0
0
NextjsHow-ToBeginner · 4 min read

How to Create a Blog in Next.js: Step-by-Step Guide

To create a blog in Next.js, build pages inside the pages folder, use dynamic routes like [slug].js for individual posts, and fetch post data with getStaticProps and getStaticPaths for static generation. This setup lets you render blog posts fast and SEO-friendly.
📐

Syntax

In Next.js, blog pages are created using the pages directory. Dynamic routes use square brackets like [slug].js to handle different blog posts. You fetch data with getStaticProps for static content and getStaticPaths to define which pages to generate.

  • pages/index.js: Main blog list page.
  • pages/posts/[slug].js: Dynamic page for each blog post.
  • getStaticProps: Fetches data at build time.
  • getStaticPaths: Defines dynamic routes to pre-render.
javascript
export async function getStaticPaths() {
  return {
    paths: [
      { params: { slug: 'first-post' } },
      { params: { slug: 'second-post' } }
    ],
    fallback: false
  };
}

export async function getStaticProps({ params }) {
  const postData = getPostData(params.slug);
  return {
    props: {
      postData
    }
  };
}

export default function Post({ postData }) {
  return (
    <article>
      <h1>{postData.title}</h1>
      <div>{postData.content}</div>
    </article>
  );
}
💻

Example

This example shows a simple blog with a homepage listing posts and dynamic pages for each post using static generation.

javascript
import fs from 'fs';
import path from 'path';
import Link from 'next/link';

const postsDirectory = path.join(process.cwd(), 'posts');

export function getSortedPostsData() {
  const fileNames = fs.readdirSync(postsDirectory);
  const allPostsData = fileNames.map(fileName => {
    const slug = fileName.replace(/\.md$/, '');
    const fullPath = path.join(postsDirectory, fileName);
    const fileContents = fs.readFileSync(fullPath, 'utf8');
    return {
      slug,
      title: fileContents.split('\n')[0].replace('# ', ''),
      content: fileContents
    };
  });
  return allPostsData;
}

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData
    }
  };
}

export default function Home({ allPostsData }) {
  return (
    <main>
      <h1>My Blog</h1>
      <ul>
        {allPostsData.map(({ slug, title }) => (
          <li key={slug}>
            <Link href={`/posts/${slug}`}>{title}</Link>
          </li>
        ))}
      </ul>
    </main>
  );
}

// pages/posts/[slug].js
import fs from 'fs';
import path from 'path';

const postsDirectory = path.join(process.cwd(), 'posts');

export async function getStaticPaths() {
  const fileNames = fs.readdirSync(postsDirectory);
  const paths = fileNames.map(fileName => ({
    params: {
      slug: fileName.replace(/\.md$/, '')
    }
  }));
  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const fullPath = path.join(postsDirectory, `${params.slug}.md`);
  const fileContents = fs.readFileSync(fullPath, 'utf8');
  const title = fileContents.split('\n')[0].replace('# ', '');
  const content = fileContents.split('\n').slice(1).join('\n');
  return {
    props: {
      postData: { title, content }
    }
  };
}

export default function Post({ postData }) {
  return (
    <article>
      <h1>{postData.title}</h1>
      <p>{postData.content}</p>
    </article>
  );
}
Output
<main><h1>My Blog</h1><ul><li><a href="/posts/first-post">First Post</a></li><li><a href="/posts/second-post">Second Post</a></li></ul></main>
⚠️

Common Pitfalls

Common mistakes include not using getStaticPaths with dynamic routes, which causes 404 errors, or forgetting to return fallback: false when you want all pages pre-built. Another pitfall is not reading post data correctly or not placing markdown files in the right folder.

Also, avoid fetching data inside the component directly for static pages; use getStaticProps instead.

javascript
/* Wrong: Missing getStaticPaths causes build errors for dynamic routes */
export async function getStaticProps({ params }) {
  // fetching post data
}

export default function Post({ postData }) {
  return <div>{postData.title}</div>;
}

/* Right: Include getStaticPaths to define dynamic routes */
export async function getStaticPaths() {
  return {
    paths: [
      { params: { slug: 'example-post' } }
    ],
    fallback: false
  };
}

export async function getStaticProps({ params }) {
  // fetching post data
}

export default function Post({ postData }) {
  return <div>{postData.title}</div>;
}
📊

Quick Reference

  • pages/index.js: List all blog posts with links.
  • pages/posts/[slug].js: Dynamic page for each post.
  • getStaticProps: Fetch data at build time.
  • getStaticPaths: Define which dynamic pages to generate.
  • posts/ folder: Store markdown or JSON files for blog content.

Key Takeaways

Use dynamic routes with [slug].js to create individual blog post pages.
Fetch blog data at build time using getStaticProps and getStaticPaths for fast, SEO-friendly pages.
Store blog content in a folder like posts/ and read files to generate pages.
Always define getStaticPaths for dynamic routes to avoid 404 errors.
Link posts on the homepage using Next.js Link component for client-side navigation.