Blog Miranti

Creating a blog using Next.js 14 and Markdown

This article explains how to use a customized version of the MUI Blog template, with enhanced Next.js 14 integration and extra Material UI functionalities.

Continue reading...

Creating a blog using Next.js 14 and Markdown

Tue Feb 20 2024

This article explains how to use a customized version of the MUI Blog template, with enhanced Next.js 14 integration and extra Material UI functionalities.


npx create-next-app@latest  \
    --typescript            \
    --eslint --app          \
    --use-npm               \

cd <your-blog-name>

npm run dev

Then open the browser and navigate to http://localhost:3000 to get familiar with the generated blog, already populated with some example blog posts.

Blog structure

├── (posts)
│   ├── br
│   │   ├── 2024
│   │   │   └── 02
│   │   │       └── 20
│   │   │           └── blog-next-mui
│   │   │               ├── body.mdx
│   │   │               └── metadata.ts
│   │   └── page.tsx
│   ├── en
│   │   ├── 2024
│   │   │   └── 02
│   │   │       └── 20
│   │   │           └── blog-next-mui
│   │   │               ├── body.mdx
│   │   │               └── metadata.ts
│   │   └── page.tsx
│   └── fr
│       └── page.tsx
├── globals.css
├── locales
│   ├── br.ts
│   ├── en.ts
│   ├── fr.ts
│   └── index.ts
├── settings.ts
└── theme.ts

Posts directory

The blog posts are organized inside the app/(posts) directory. A post is made of 2 files:

  • Markdown file - it's where the content of the post can be edited.
  • Metadata file - it's used for 3 purposes:
    1. Set the page's metadata (window title, SEO description, and keywords, etc).
    2. The titles and descriptions are also the contents that are rendered in the root page Listing of posts and the configured FeaturedPosts.
    3. The keywords are the indexes that allow the posts be filtered by the Category links at the header of the page.
export const metadata = {
  // HTML meta title (Window Title)
  title: '...',
  // HTML meta description, and also the summary that appeans in the
  // Featured posts and Posts listings.
  description: '...',
  // HTML meta keywords.
  // If they match with the blog categories, they are used to filter
  // posts by category.
  keywords: ['Category 1', 'Category 2', ...],

Locales directories

Although the posts and metadata contents are internationalized along the blog posts directories themselves, there are other structural elements in the page requiring internationalization like the Blog title, the sections headers (main section, sidebar, featured posts, etc). The purpose of the app/locales files is to provide I18n for such elements of the blog.


  • Select the Main Featured Post that is displayed in the Hero section of the page.
  • Select two featured posts that are presented before the footer of the page.
  • Configure the social links (Github, LinkedIn, etc).
  • Configure the blog's Categories' filters.


Adding a new post in Brazilian Portuguese at April 30, 2024:

  • Create the post directory: app/(posts)/br/2024/04/30/new-blog-post
  • Create the metadata.ts file with post title, description, and keywords.
  • Create the file body.mdx with the contents of the post written in Markdown.

Adding another language

To add support to another language:

  • Add the new language icon to the app/blog/LanguageSelector component and to the app/settings variable supportedLanguagesValues.
  • Create a new app/locales/xx.ts and export it from the dictionaries module app/locales/index.ts.
  • Create a new app/(posts)/xx/page.tsx.

The example below would be the contents of a Spanish version of the blog:

# app/(posts)/es/page.tsx

import type { Metadata } from "next"

import { t } from '@/app/i18n'
import Blog from '@/app/blog/Blog'

export const metadata: Metadata = {
  title: t('blogTitle', 'es'),
  description: t('blogDescription', 'es'),

interface PageProps {
  params: any
  searchParams: any

export default async function Page (props: PageProps) {
  props.params.lang = 'es'
  return <Blog {...props} />

Environment Variables

  • NEXT_PUBLIC_BASE_URL: it's used form app/sitemap.tsx for automatic sitemap generation
  • GTAG_ID: Google Analytics settings (app/layout.tsx).


Although this is a hands-on guide demonstrating how to use the enhanced blog template, the next articles of this series will explain step-by-step how to work with Next.js 14 and MUI:


I'm an engineer with a bachelor's degree from ITA, graduating in 2004 with a focus on Computer Engineering and academic research on Bayesian learning algorithms applied to mobile robot simulations. Proficient in a range of programming languages, including Java, Ruby on Rails, React, and Next.js, I thrive on tackling challenging projects. My career journey spans developing software for the aviation industry from 2005 to 2010, followed by significant contributions to payments processing start-ups until 2017. As the CTO at Donorbox from 2017 to 2021, I spearheaded the company's growth initiatives. Currently, I'm engaged at 7GEN where I lead the design of software solutions for managing fleets of electric vehicles. This role involves integrating Telematics APIs and Charging Stations Management Systems based on the OCPP Protocol, contributing to the advancement of sustainable transportation solutions.