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.