KeynouProgramming
Articles
Sign InGet Started
© 2026 Programming Keynou. All rights reserved.
Privacy PolicyTerms of ServiceContact
Back to Articles

Building a Blog with NextJS: Step by Step Tutorial

12/9/2025
Python Programming
Next.jsDockerCloud Deployments

Building a Blog with NextJS: Step by Step Tutorial

Creating a scalable, performant blog is crucial for startup founders. Whether you want a simple company blog or a technical publishing platform, understanding how to leverage modern tools like Next.js, with an eye for Cloud Deployments and Docker, can make the difference between a fast, scalable product and one that quickly becomes unmanageable. In this tutorial, you’ll learn—line by line, concept by concept—how to build, containerize, and deploy a fully functional Next.js blog. Each technical term is unpacked before we dig deeper, ensuring complete comprehension, even for those coming from a Python programming background.

What is Next.js? The Framework Essentials

Next.js is a React-based framework for building web applications. While React itself is a library for building UI components, Next.js adds critical capabilities like server-side rendering (SSR), static site generation (SSG), API routes, and file-based routing. In plain English, Next.js turns React from a UI builder into a true web application framework—handling rendering, routing, data fetching, and more.

  • SSR (Server-Side Rendering): Renders the page on the server before sending HTML to the browser, improving SEO and initial load times.
  • SSG (Static Site Generation): Builds HTML at build time for faster, CDN-friendly sites.
  • API Routes: Allows you to create backend endpoints within your Next.js project, handling form submissions or integrating with databases.
  • File-based Routing: Every file inside /pages automatically becomes a route.

For startup founders, these features mean faster MVPs, SEO-ready content, and flexibility to scale from prototype to production—all with a single tool.

Project Initialization: Setting Up Next.js

Let’s walk step-by-step through project initialization. You only need Node.js (a runtime that lets you run JavaScript outside the browser) and npm/yarn (package managers).


npx create-next-app@latest nextjs-blog
cd nextjs-blog
npm run dev

This scaffolds a project with sensible defaults. Open http://localhost:3000—you’ll see your starter Next.js blog.

Understanding the File Structure: What Goes Where?

After creation, your folder looks like this:


/pages
  index.js      // Home page. Route: /
  _app.js       // Customizes how pages initialize
  api/
    hello.js    // API route. Route: /api/hello
/public
  favicon.ico, etc.
// ...other files (config, readme)
  • pages/: Each file = route. about.js → /about
  • api/: Backend endpoints, not visible as pages
  • public/: Static files (images, icons, robots.txt)
  • _app.js: Customizes root of all pages (wrappers, styles, providers)

This file-centric design reduces boilerplate and makes scaling easier. As you add new pages or API endpoints, the structure remains simple and self-documenting—critical for startups where team growth can be rapid.

Data Sources: Markdown vs. Headless CMS

Blogs need content. In Next.js, you can read from local Markdown files or pull content from a remote Headless CMS. Let's explain both terms:

  • Markdown: A lightweight markup language for formatting text (e.g., **bold** becomes bold). Storing blogs as .md files keeps things simple and version-controlled.
  • Headless CMS: A content management system that only provides APIs to fetch/post data. Example: Contentful, Sanity, Strapi.

For most startups, starting with Markdown is easiest—you can always migrate later. Let’s wire this up.

Static Site Generation in Next.js: How and Why?

Static Site Generation (SSG) means Next.js builds your blog pages as HTML at build time—so when users request a page, it’s already rendered and ready to go. This is ideal for blog posts that don’t change every minute, providing fast load times and maximum SEO performance.

Step-by-Step: Listing Blog Posts from Markdown

Suppose you have blog post files:


/posts
  hello-world.md
  scaling-nextjs.md

Let’s install dependencies to parse Markdown:


npm install gray-matter remark remark-html
  • gray-matter: Parses "frontmatter" (YAML metadata)
  • remark & remark-html: Converts markdown text to HTML

Now, create a utility to fetch post data. Save as lib/posts.js:


import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'

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

export function getSortedPostsData() {
  const fileNames = fs.readdirSync(postsDirectory)
  const allPostsData = fileNames.map(fileName => {
    const id = fileName.replace(/\.md$/, '')
    const fullPath = path.join(postsDirectory, fileName)
    const fileContents = fs.readFileSync(fullPath, 'utf8')
    const matterResult = matter(fileContents)
    return {
      id,
      ...matterResult.data
    }
  })
  return allPostsData.sort((a, b) => (a.date < b.date ? 1 : -1))
}

This reads all .md files, parses each file’s metadata (title, date), and returns a sorted array—ready for listing.

Populating Your Index Page with Blog Posts

Next.js lets you pre-fetch your blog data at build time via the special getStaticProps function.


// pages/index.js
import { getSortedPostsData } from '../lib/posts'

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

export default function Home({ allPostsData }) {
  return (
    <section>
      <h2>Blog</h2>
      <ul>
        {allPostsData.map(({ id, date, title }) => (
          <li key={id}>
            <a href={`/posts/${id}`}>{title}</a>
            <br />
            <small>{date}</small>
          </li>
        ))}
      </ul>
    </section>
  )
}

This fetches all posts for your home page. When you run next build, the blog index is generated statically, making load times near-instant.

Dynamic Routing: Individual Blog Post Pages

How do we render each blog post at its own URL? Next.js supports dynamic routing—file names in [brackets] create parameterized routes.

  • pages/posts/[id].js → /posts/hello-world, /posts/scaling-nextjs

// pages/posts/[id].js
import { getAllPostIds, getPostData } from '../../lib/posts'

export async function getStaticPaths() {
  const paths = getAllPostIds()
  return {
    paths,
    fallback: false
  }
}

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

export default function Post({ postData }) {
  return (
    <article>
      <h1>{postData.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
    </article>
  )
}

The getStaticPaths function tells Next.js which URLs to generate. getStaticProps fetches content for each post. Each page is pure HTML by the time it hits your browser—excellent for load speed and search engines.

Styling: CSS Modules in Next.js

CSS Modules let you write local, component-scoped CSS files. This means a style defined in Home.module.css affects only the associated component, not your whole site—solving the "global CSS bloat" problem.

  • Create styles/Home.module.css
  • Import it: import styles from './Home.module.css'
  • Apply with className={styles.classNameHere}

// styles/Home.module.css
.title {
  color: #0070f3;
  font-size: 2rem;
}

// pages/index.js
<h2 className={styles.title}>Blog</h2>

This creates encapsulated, maintainable, and conflict-free styles—ideal when working in fast-moving teams.

API Routes: When You Need Backend Logic

API routes let you add backend logic inside your Next.js project without spinning up a separate Express or Django server. This is perfect for handling newsletter signups, forms, or integrating third-party APIs.


// pages/api/subscribe.js
export default function handler(req, res) {
  if (req.method === 'POST') {
    // process data, save to DB or send email
    res.status(200).json({ message: 'Subscription successful'})
  } else {
    res.status(405).end() // Method Not Allowed
  }
}

You now have a backend endpoint at /api/subscribe, deployable alongside your frontend.

Performance, Scalability, and Trade-offs: What Next.js Does Internally

For advanced readers, Next.js optimizes pages during the build with automatic code splitting (only loads JavaScript needed for that page), prefetching links (loads linked pages in the background), and incremental static regeneration (updates static pages post-deploy without redeploying the entire site).

  • SSR vs. SSG: SSR is great for user-specific data (e.g., dashboards), SSG for largely static content (e.g., blogs, docs). SSG scales better (serving static files on a CDN is cheap and fast).
  • Build Time: Very large sites with thousands of posts can see long build times. Consider strategies like getStaticPaths with fallback or using a Headless CMS with on-demand ISR.

Dockerizing the Next.js Blog: Why and How?

“Dockerizing” means packaging your application into a container—a consistent environment that can run anywhere (your laptop, AWS, Google Cloud) without “it works on my machine” issues. Docker bundles OS-level dependencies, Node.js, your app, and runtime all together.


# Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
COPY . .
RUN yarn build

FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["yarn", "start"]

Build your image:


docker build -t nextjs-blog .
docker run -p 3000:3000 nextjs-blog
  • FROM node:18-alpine: Starts from a lightweight Node.js image.
  • Yarn build: Compiles your app (static and server files).
  • EXPOSE 3000: Makes the app accessible on port 3000.

With Docker, your blog becomes portable—deployable to any cloud in seconds.

Cloud Deployments: Taking Next.js to Production

Cloud Deployment means running your application on a provider’s infrastructure (like Vercel, AWS, GCP, Azure, or DigitalOcean). These platforms can run your Docker image, manage scaling, security, and automatic updates.

  1. Push your image to a cloud container registry (like Amazon ECR or Docker Hub).
  2. Use the provider's Docker orchestration (e.g., AWS ECS, Google Cloud Run) to deploy and scale.
  3. For zero-config, Vercel (creators of Next.js) is excellent for SSG/SSR, giving instant preview URLs and edge scaling with minimal setup.

Deploying with Docker in the cloud enables you to:

  • Maintain consistency across testing, staging, and production environments.
  • Scale horizontally (run multiple containers behind a load balancer).
  • Add environment secrets and CI/CD pipelines for rapid iteration.

Practical Examples and Real-World Use Cases

Consider a startup that needs:

  • An engineering blog for SEO and talent recruitment.
  • Docs site for a developer API.
  • Custom leads forms with spam filtering.

Next.js handles static docs, SSG for blog posts, plus custom API endpoints for leads forms—all in one repo, all deployable as a container or serverless functions. For example, a fast-growing fintech startup could run the same blog build locally (via Docker), in test environments, and deploy to AWS Fargate for production—ensuring bugs don’t arise from “different environments.” Engineers can iterate on the UI quickly, and founders can push critical content instantly.

Conclusion: What You've Learned and Next Steps

In this deep technical walkthrough, you’ve learned how to:

  • Set up a Next.js blog from scratch with clear folder organization.
  • Source content from Markdown for rapid iteration and versioning.
  • Use Static Site Generation for speed and SEO, with dynamic routing for individual posts.
  • Introduce CSS Modules for maintainable, scalable styling.
  • Add API routes for custom forms or backend logic without extra servers.
  • Dockerize your application for consistency and portability.
  • Deploy to the cloud using Docker or serverless platforms for horizontal scaling and operational ease.

Armed with these techniques, startup founders with a Python background can confidently build, ship, and scale a robust blog platform using Next.js. The next logical steps include automating builds with CI/CD, integrating with a headless CMS for non-technical authors, or extending your application with advanced features like authentication, analytics, and internationalization.

0 Comments

Comments

Loading comments...

Popular Posts

Recent Posts

Related Posts