How to Use Markdown to Make Static Pages and Blog Posts

How to Use Markdown to Make Static Pages and Blog PostsHow to Use Markdown to Make Static Pages and Blog Posts

Oct 28, 2025 - 9 min

Roko Ponjarac

Roko Ponjarac

Software Engineer


You can change the content of your website without changing React components. You write files in plain text. The system takes care of structure, rendering, and SEO. This method keeps content quick, consistent, and easy to grow.

This article talks about how we use Markdown to make static pages and blog posts on our projects. The process has a strict structure that keeps the content the same across languages and settings.

Why use Markdown?

With Markdown, you have full control over your content with very little syntax. You concentrate on writing. The system takes care of parsing, outputting HTML, and metadata.

Important benefits for you:

  • You change content without using frontend code.
  • You use Git to version your content.
  • You support more than one language and have a clear file structure.
  • You keep building quickly by processing on the server side.

During build time or server rendering, the server processes all markdown files.

An Overview of the System

A small number of libraries are needed for the markdown pipeline to work.

LibraryFunction
GraymatterReads metadata from blog posts.
RemarkProcesses the syntax for markdown.
Remark-gfmAdds strikethrough, tables, and task lists.
remark-rehypeChanges markdown into HTML.
rehype-rawLets you use HTML inline.
rehype-stringifyMakes the final HTML.

You write in Markdown. The system returns back HTML that is clean.

Structure of the Directory

All of the files are in the src/files.

Static pages are in the following folders:

  • src/files/static/en
  • src/files/static/hr

Blog posts: src/files/blog/en and src/files/blog/hr

There is a folder for each language. There is a version of every page or post in both languages. The kebab case is used for file names. Shared slugs are what language switching depends on.

This layout keeps routing, SEO, and translations in sync.

Pages that don't change

Static pages house legal papers, policies, and other general information. There is only markdown in these files. There is no metadata block at the top.

The whole file changes to HTML.

You use headings, lists, tables, code blocks, links, images, and HTML that is inline. GitHub-style Markdown is still fully supported.

Making a Static Page

Step one. Make files that are the same for each language. Example:

  • src/files/static/en/terms-of-service.md
  • src/files/static/hr/terms-of-service.md

File names must be the same in all languages.

Step two. In the App Router, add a route for the page. Using locale, type, and file name, the route obtains content through getPage. The page provides a 404 error if the file does not exist.

import { getPage } from '@/lib/page';

const TermsOfService = async ({ params }: PageProps) => {
  const { locale } = await params;
  const content = await getPage(locale, 'static', 'terms-of-service');

  if (!content) {
    notFound();
  }

  return (
    <Layout>
      <StaticPage content={content} />
    </Layout>
  );
};

Step three. Add metadata for SEO. You set the title and description in translation files. There is a different version for each language.

Step four: Add paths that are specific to your location. You set up the routing config to map English and Croatian URLs. This step makes things clearer for users and helps with SEO.

The page automatically shows up in both languages after setup.

Blog Entries

YAML frontmatter adds to markdown in blog posts. This block sets metadata for SEO, routing, and listing pages.

Every blog post has:

  • Slug
  • Title
  • The path to the cover image
  • Date of publication
  • Category
  • Featured Flag
  • Name of the author
  • Optional avatar for the author

The system calculates the estimated reading time based on the length of the content.

Rules for Frontmatter

The front matter is at the top of the file. Three dashes (---) mark the beginning and end. Fields must be typed exactly. Invalid categories or missing fields cause builds to fail. There are only four categories: frontend, backend, design, and business. The slug is the same for both language versions of the same post.

---
title: My Blog Post Title
slug: my-blog-post-title
image: /images/blog/my-post-cover.webp
date: 2025-01-15
category: category-name
featured: false
author:
  name: John Doe
  avatar: /images/avatars/john.webp
---

Making a Blog Post

First step. Make a cover photo. The photo should have a resolution of 1200 by 630 pixels. Where: public/images/blog. Name the file.

Step two: Make markdown files for each language. Location: src/files/blog/en / src/files/blog/hr The slug should match the file name.

Third step. Write something. Use the headings to organise the post. Lists, tables, and code blocks can be helpful. Ensure that your paragraphs are concise and focused.

Step four. Include avatars for authors who are not required. Put pictures in public/images/avatars. In the front matter, point to the path.

Step five: Conduct a test.

  1. Turn on the dev server.
  2. Look at the list of blogs.
  3. Go to the post page.
  4. Verify both languages.
  5. Please review the pictures and the time it takes to read.

Pages with Frequently Asked Questions

There is a strict markdown pattern for FAQ pages.

  • Single hash headings (#) show what groups are.
  • Questions are defined by double hash headings (##).
  • The answer is everything below a question until the next heading.

The system automatically breaks down groups and questions. Answers can be fully formatted with markdown.

This structure provides accordion parts with the necessary content without requiring any additional setup.

API for Content

All access to markdown goes through helper functions.

FunctionReturns
getPageHTML for a static page.
getBlogPostsList of post metadata.
getBlogPostA full post with all the content.
// Get HTML for a static page
const content = await getPage('en', 'static', 'privacy-policy');

// Get all blog posts
const posts = getBlogPosts('en');

// Get a single blog post by slug
const post = await getBlogPost('en', 'my-blog-post-slug');

You should never touch filesystem logic in components.

Checklist for Content

For pages that don't change:

  • There are both languages.
  • There are ways to get there.
  • There is metadata.
  • Paths are useful.
  • Pages show up.

For posts on a blog:

  • There is a cover image.
  • There are fields in the front matter.
  • Slug matches in both languages.
  • The category is still valid.
  • The post shows up on the list.
  • The post page loads just fine.

Problems that happen a lot

  • If posts are missing from the blog, it's usually because they are in the wrong folder or have invalid frontmatter.
  • If you see slug errors, it means there are problems with the YAML syntax.
  • Often, incorrect paths or file names lead to image problems.
  • After making changes, localised routes need to be restarted on the server.

In short

This markdown system makes it easier to work with code and content. You only write content once. The system takes care of architecture, rendering, and localisation. You send things out faster. The content stays the same. Scaling content is still easy.

Ready to talk?

Send a brief introduction to schedule a discovery call. The call focuses on your challenges and goals and outlines the first steps toward the right digital solution.

How to Use Markdown to Make Static Pages and Blog Posts | Workspace