Migrating My Blog from Jekyll to Next.js and Tailwind CSS
A modern web development workflow for blogging, Introducing Tailwind Nextjs Starter Blog
10 min read
After a few years of running my blog on , I decided it was time for an upgrade. Jekyll served me well, but as my needs evolved, I found myself wanting more flexibility, better performance, and a more modern development workflow. Enter , , and a host of other modern web development tools that have transformed my blogging experience. Here's a rundown of the migration process and the benefits I’ve enjoyed since making the switch.
Why Migrate from Jekyll?
Jekyll is a static site generator that is simple, reliable, and supported by GitHub Pages. However, it has its limitations:
- Performance: While Jekyll is fast for simple blogs, it can become sluggish as your content grows.
- Customization: Advanced customization often requires diving into Liquid templates and custom plugins, which can be cumbersome.
- Modern Workflow: Jekyll lacks some modern development features like hot-reloading and advanced state management.
Choosing Next.js and Tailwind CSS
Next.js, a React-based framework, offers the perfect balance of flexibility and performance:
- Server-Side Rendering (SSR) and Static Site Generation (SSG): Next.js allows you to choose between SSR and SSG, optimizing performance and SEO.
- Dynamic Routing: Easy creation of dynamic routes without complex configuration.
- API Routes: Built-in API routes simplify backend logic integration.
- Tailwind CSS complements Next.js by providing a utility-first CSS framework that speeds up styling and ensures consistency.
Tailwind Nextjs Starter Blog
I believe in reusing existing solutions to save time and effort, and a quick search led me to an amazing starting point: the . This starter template provided a solid foundation, integrating Next.js and Tailwind CSS with additional features like MDX support, theme switching, and pre-configured styles.
This is a
, blogging starter template. Probably the most feature-rich Next.js markdown blogging template out there. Comes out of the box configured with the latest technologies to make technical writing a breeze. Easily configurable and customizable. Perfect as a replacement to existing Jekyll and Hugo individual blogs. The main features that I relied and extended on are:- Easy styling customization and Mobile-friendly view with and primary color attribute
- for managing content
- Server-side syntax highlighting with line numbers and line highlighting via
- Math display supported via
- Citation and bibliography support via
- Automatic image optimization via
- Flexible data retrieval with
- Preconfigured security headers
- SEO friendly with RSS feed, sitemaps
The Template Structure
First, lets understand the different folders/components of the template:
static
Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public
can then be referenced by your code starting from the base URL /
.
For our template, we have a static
folder that contains images to be used in the blog, logos,icons and favicons.
scripts
This folder contains scripts to help with the development and maintenance of the blog.
- The
build.mjs
script is used to perform a bunch of steps post theyarn run build
command. It is used to generate the RSS feed and the tags and categories pages. - The
rss.mjs
script is used to generate the RSS feed for the blog.
NOTE
Why .mjs
extension?
Since Node.js was created, the ECMAScript module system (which uses import and export) has become standard and Node.js has added support for it. However, Node. will treat .js files as CommonJS (which is the default module system for the project) unless package.json says "type": "module"
or the file extension is .mjs
.
data
The data
folder contains the site metadata, authors, and blog posts in .mdx
. The markdownToHtml
function is used to convert markdown .mdx
to HTML.
authors
: contains the author information for the blog posts and is used to populate theabout
page. This can be extended to allow multiple authors.blog
: contains the blog posts inmdx
format. The folders are used to categorize the blog posts.metadata
: contains the site metadata like navigation links, site title, description, etc. We will discuss this in more details in the metadata section
layouts
The layouts
folder contains the main templates used in the pages. The main layout is MainLayout.js
which is used to wrap all the pages. The PostLayout.js
is used to wrap all the blog posts.
lib
The lib
folder contains utility functions and configurations used throughout the blog.
contentLayer
: contains the content layer "plugins"/"scripts" for the blog posts and projects.computedFields.js
: contains the computed fields for the blog posts. Those are fields that are generated based on the content of the blog post or its metadata like thereadingTime
ortoc
(table of contents).contentFields.js
: defined the fields that appear in the frontmatter for the different types of content (author, post, project, etc.).generatedCategories.mjs
: Loops through all the posts and generates the categories for the blog posts.generatedTags.mjs
- generates the tags for the blog posts.projectFields.js
- contains the project fields for the projects page.structuredData.js
- contains the structured data for the blog posts.
mdx
- contains the utility functions for the MDX files.remark-code-title.js
- adds a title to the code blocks.rehype-citation.js
- adds citation support to the MDX files.rehype-katex.js
- adds math display support to the MDX files.
components
The components
folder contains the React components used in the blog. The MDXComponents.js
file contains the components used to render the MDX files. The social-icons
folder contains the SVG icons for social media.
css
The css
folder contains the tailwind.css file which contains the tailwind stylesheet. The prism.css
file contains the styles associated with the code blocks.
app
The app
folder contains the main application files. The pages
folder contains the pages to route to. The api
folder contains the API routes. The components
folder contains the components used in the pages. The styles
folder contains the global styles.
Sample posts
Quick Start Guide
- Try installing the starter using the new :
It supports the updated version of the blog with Contentlayer, optional choice of TS/JS and different package managers as well as more modularized components which will be the basis of the template going forward.
Alternatively to stick with the current version, TypeScript and Contentlayer:
or JS (official support)
- Personalize
siteMetadata.js
(site related information) - Modify the content security policy in
next.config.js
if you want to use any analytics provider or a commenting solution other than giscus. - Personalize
authors/default.md
(main author) - Modify
projectsData.js
- Modify
headerNavLinks.js
to customize navigation links - Add blog posts
- Deploy on Vercel
Development
First, run the development server:
Open with your browser to see the result.
You can start editing the page by modifying pages/index.js
. The page auto-updates as you edit the file.
Extend / Customize
data/siteMetadata.js
- contains most of the site related information which should be modified for a user's need.
data/authors/default.md
- default author information (required). Additional authors can be added as files in data/authors
.
data/projectsData.js
- data used to generate styled card on the projects page.
data/headerNavLinks.js
- navigation links.
data/logo.svg
- replace with your own logo.
data/blog
- replace with your own blog posts.
public/static
- store assets such as images and favicons.
tailwind.config.js
and css/tailwind.css
- contain the tailwind stylesheet which can be modified to change the overall look and feel of the site.
css/prism.css
- controls the styles associated with the code blocks. Feel free to customize it and use your preferred prismjs theme e.g. .
components/social-icons
- to add other icons, simply copy an svg file from and map them in index.js
. Other icons use .
components/MDXComponents.js
- pass your own JSX code or React component by specifying it over here. You can then call them directly in the .mdx
or .md
file. By default, a custom link and image component is passed.
layouts
- main templates used in pages.
pages
- pages to route to. Read the for more information.
next.config.js
- configuration related to Next.js. You need to adapt the Content Security Policy if you want to load scripts, images etc. from other domains.
Post
Frontmatter
Frontmatter follows .
Currently 7 fields are supported.
title (required)
date (required)
tags (required, can be empty array)
lastmod (optional)
draft (optional)
summary (optional)
images (optional, if none provided defaults to socialBanner in siteMetadata config)
authors (optional list which should correspond to the file names in `data/authors`. Uses `default` if none is specified)
layout (optional list which should correspond to the file names in `data/layouts`)
canonicalUrl (optional, canonical url for the post for SEO)
Here's an example of a post's frontmatter:
---
title: 'Introducing Tailwind Nexjs Starter Blog'
date: '2021-01-12'
lastmod: '2021-01-18'
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'Looking for a performant, out of the box template, with all the best in web technology to support your blogging needs? Checkout the Tailwind Nextjs Starter Blog template.'
images: ['/static/images/canada/mountains.jpg', '/static/images/canada/toronto.jpg']
authors: ['default', 'sparrowhawk']
layout: PostLayout
canonicalUrl: https://tailwind-nextjs-starter-blog.vercel.app/blog/introducing-tailwind-nextjs-starter-blog
---
Compose
Run node ./scripts/compose.js
to bootstrap a new post.
Follow the interactive prompt to generate a post with pre-filled front matter.
Deploy
Vercel
The easiest way to deploy the template is to use the from the creators of Next.js. Check out the for more details.
Netlify / GitHub Pages / Firebase etc.
As the template uses next/image
for image optimization, additional configurations have to be made to deploy on other popular static hosting websites like or . An alternative image optimization provider such as Imgix, Cloudinary or Akamai has to be used. Alternatively, replace the next/image
component with a standard <img>
tag. See for more details.
The API routes used in the newsletter component cannot be used in a static site export. You will need to use a form API endpoint provider and substitute the route in the newsletter component accordingly. Other hosting platforms such as Netlify also offer alternative solutions - please refer to their docs for more information.
Support
Using the template? Support this effort by giving a star on GitHub, sharing your own blog and giving a shoutout on Twitter or be a project .
Licence
©