TheDataGuy Migrated From Jekyll To Hugo

hugo , jekyll

I took a long break from writing blogs due to some personal reasons. I wanted to write, but couldn’t achieve it. After a year, I revisited my blog and the google analytics page. Surprisingly im getting the same amount of traffic even though I didn’t publish any new posts. So now I want to restart my blogging hobby with fresh content, design, and a new framework for my blog. This blog is about how I migrated my blog from Jekyll to Hugo.

Hugo vs Jekyll

Old Blog with Jekyll: #

Nothing wrong with the Jekyll platform, I had around 100+ posts/pages. It was a one-time setup, just copy the theme and put the posts, and everything will be taken care of by Github(Yes, I was using GitHub for hosting). People say that building time in Jekyll is a nightmare, but I don’t care about it. But the security updates with Ruby gems are always a problem for me. I have to keep an eye on GitHub notifications and update the gems(because I only put post files into the repo, no build on local).

Why Hugo: #

I closely follow Werner Vogels’s blog and I noticed that the template is so simple and clean(like my previous design) and the pages are rendering so quick. Then I wanted to know which platform he is using to host and what is that theme. Finally, I figured out it is Hugo and the theme that he is using is Lines. A surprising thing here is, I was using Sidey theme for my Jekyll is designed by the same guy Ronalds who developed the line’s theme. His work is amazing.

Kick Start Steps: #

First I need to know more about Hugo before the migrations. So I went to their website and started with basic commands like installation, creating a site, and publishing a post. Now it’s time for the migration.

Migration: #

NOTE: In all of my scripts I used \{\{ since, the webpage is not rendering if I give the { without the \. If you are trying the script then please remove the \ infront of {

Converting blog posts: #

If we google how to migrate Jekyll to Hugo, there are plenty of blogs available to do and most of them are referring to using Hugo’s native Jekyll migration option. I tried it and converted the blogs using the following commands.

cd ~/Documents/Github/
mkdir hugo-migrate-repo
hugo import jekyll my-jekyll-repo hugo-migrate-repo

This returns the following message and gave some commands to run.

Congratulations! 94 post(s) imported!
Now, start Hugo by yourself:
$ git clone test/themes/herring-cove
$ cd test
$ hugo server --theme=herring-cove

But when I try to run the hugo server command then it started giving some errors during the build.

Start building sites … 
hugo v0.104.3+extended darwin/amd64 BuildDate=unknown
ERROR 2022/11/24 19:20:36 render of "page" failed: execute of template failed: template: partials/header.html:8:10: executing "partials/header.html" at <.Hugo.Generator>: can't evaluate field Hugo in type *hugolib.pageState
Error: Error building site: failed to render pages: render of "home" failed: "/Users/bhunaneshwaranrathinasamy/Documents/GitHub/test/themes/herring-cove/layouts/index.html:9:17": execute of template failed: template: index.html:9:17: executing "index.html" at <.RSSLink>: can't evaluate field RSSLink in type *hugolib.pageState
Built in 424 ms

I tried to solve it, but I couldn’t. Then I decided to stay on Jekyll itself and started re-designing the Jekyll theme. But after a few days, again I wanted to try the Hugo with a different theme(Lines), But this time it was a success. I didn’t face any errors. May be Hugo team can fix their doc to use a different theme.

hugo import jekyll my-jekyll-repo hugo-migrate-repo
cd hugo-migrate-repo/
git clone themes/lines
hugo server --theme=lines

In this theme, I face an issue related to the Instagram token that is added to their example post. So I removed all the files from theme/lines/content/posts/

rm -rf themes/lines/content/posts/*
cp -R content/post/* themes/lines/content/posts
hugo server --theme=lines

After the conversion, the blog is working fine but, many things got broken in the blog post. Lets see how did I fix everything.

Issue #1 Github Gits not rendering: #

I added many gits links into the blog posts, but none of them are rendered. For Gits, Hugo has its native shortcode to render. So I had to replace all the Gits urls to Hugo’s shortcode. Sample Gits URL in Jekyll:

<script src=""></script>

Hugo Shortcode:

\{\{< gist BhuviTheDataGuy 2103b0a6177c62718fe91095a40e3e33 >}}

So I wrote a command to replace all the gits URLs to Hugo shortcode.

I used Macbook so I put the sed syntax as sed -i '' -E. For linux sed -i -e will work.

for file in *
sed -i '' -E '/^<script src/s~.*/([^/]*)/([^/]*)/([^/]*)([^/]*).js.*~\{\{< gist \2 \3 >}}~' $file

Issue #2 - Image path #

I used a custom shortcode in Jekyll to activate LazyLoad. Also included {{ site.baseurl }}as a prefix to the image path. So all the images that I added to the markdown file are as follows,

{% include lazyload.html image_src="/assets/architecture/migrate-gp-to-bq-airflow-sync.jpg" image_alt="airflow-sync" image_title="airflow-sync" %}

But Hugo will accept the image format as,

![Image Title](Image Location "Image Alt")
![Image Title]({{ site.baseurl }}/Image Location "Image Alt")

If the image name contains whitespaces, the image code is,

![Image Title](<Image Location> "Image Alt")

This script will replace all the file’s image paths in Hugo format. Delete {{ site.baseurl }} prefix:

cd hugo-migrate-repo/theme/lines/content/posts/
for file in *
sed -i '' -E 's/{{ site.baseurl }}//g' $file

Change the image path into Hugo format:

cd hugo-migrate-repo/theme/lines/content/posts/
for file in *
line=$(grep -n  'include lazyload.html' $file | awk -F ':' '{print $1}')
if [ -z "$line" ]
echo ""
echo $line | while read ln 
echo $file
img=$(sed -n "$ln"p $file | awk -F'=' '{print $2}' | sed 's/ image_alt//g' | sed 's/"//g') 
alt=$(sed -n "$ln"p $file | awk -F'=' '{print $4}' | sed 's/ %}//g' | sed 's/"//g')
replace="\![$alt](<$img> \"$alt\")"
sed -i '' -E "${ln}s~.*~$replace~" $file

If you are not using a custom shortcode, then the image path will look like this,


Use the following code to convert to Hugo format.

cd hugo-migrate-repo/theme/lines/content/posts/
for file in *
line=$(grep -n  '!\[\](/assets/' $file | awk -F ':' '{print $1}')
if [ -z "$line" ]
echo ""
echo $line | while read ln 
echo "this is the file "$file
img=$(sed -n "$ln"p $file | awk -F'(' '{print $2}' | sed 's/)//g') 
sed -i '' -E "${ln}s~.*~$replace~" $file

Issue #3 - Code highlight #

I used 2 different formats for code highlight.

code line 1
code line n
\{\{< highlight Language-name >}}
\{\{< /highlight  >}}

The code highlight worked fine but looks messy. So Hugo has the chroma code highlighter where we can choose different styles. In both formats, I just need to add the style flag.

```Language-name {style=vs}
```Other lines
    \{\{< highlight Language-name \{"style=vs"} >}}
    \{\{< / highlight  >}}

To update the syntax, first I listed down all the code highlight languages.

cd /to/posts/folder/
grep -rn '```' . | awk -F ':' '{print $3}' | sort -u

This returns the list of unique code highlighting languages.


Use the following code to update this syntax with the style flag. This code is

for updating the `bash` syntax, repeat the same for all other languages.
for file in *
sed -i '' -E "s~\`\`\`sql~\`\`\`sql {style=vs}~g" $file

For the syntax with \{\{< highlight >}} shortcode, list down all the languages.

grep -rn '\{\{< highlight' . | awk -F ':' '{print $3}' | sort -u
\{\{< highlight shell >}}
\{\{< highlight json >}}
\{\{< highlight python >}}

Then add a style flag by using the following command.

cd /path/to/posts/folder/
for file in * 
sed -i '' -E 's/\{\{< highlight yml >}}/\{\{< highlight yml "style=vs" >}}/g' $file

Issue #4 - Update URL format #

In Jekyll all the posts files are formatted as and the URL as We can set the same URL format in the config.toml file.

  posts = "/:filename"

But after the conversion, the URL shows as So I need to rename the files without YYYY-MM-DD.

cd /path/to/posts/folder/
for file in *
mv $file $new

Customization: #

#1 Google fonts for Title and content #

The default font for the line’s theme is Open Sans but still, it doesn’t look good to me. So I wanted to use google font for the post title and post content. Go to Google Fonts and select the font you want to use and its weight. Then on the right side pane, and select on @import option. Copy the content and paste it into the style.scss or whatever the main CSS file of your theme.

@import url('');
@import url('[email protected];500;700;1000&display=swap');

// for the page content
body {
    color: #353535;
    line-height: 2;
    letter-spacing: 0.3px;
    font-family: 'Nunito', sans-serif;
    font-weight: 400;
    font-size: 17px;
    border-radius: 3px;

// For headings
.title {
    display: block;
    font-size: 1.8em;
    margin-block-start: 0.83em;
    margin-block-end: 0.83em;
    margin-inline-start: 0px;
    margin-inline-end: 0px;
    font-weight: 300;
    font-family: 'Noto Serif', serif;
    text-align: left;
    margin-top: 0px;

#2 Custom blockquote section #

The blockquote needs to be in a different style, so that it’ll highlight that section. Here is my custom blockquote css.

blockquote {
    border-left: 5px solid #353535;
    padding-left: 1rem;
blockquote {
    margin: 1.5em 0 1.5em;
    padding: 0 1em 0 2.5em;

    font-family: 'PT Serif', serif;
    font-size: 16px;
    color: #393636;
    padding:1.2em 30px 1.2em 75px;
    border-left:8px solid #c0c4c3 ;
    position: relative;
    border-radius: 5px;
    font-weight: 400;
    content: "\201C";
    color: #00adef;
    position: absolute;
    left: 10px;
    content: '';
blockquote span{
    font-style: normal;
    font-weight: bold;

#3 Code highlight with copy button #

I want to display the copy button for all the code block sections. I referred this blog to create that copy button and it has to be displayed on top of the code highlight box. So I added the css as below.

.highlight-wrapper {
    display: block;
  /* Start: Turn off individual column border, margin, and padding when line numbers are showing */
  .highlight-wrapper .lntd pre {
      padding: 0;
  .chroma .lntd pre {
      border: 0px solid #ccc;
  .chroma .lntd:first-child {
    padding: 7px 7px 7px 10px;
    margin: 0;
  .chroma .lntd:last-child {
    padding: 7px 10px 7px 7px;
    margin: 0;
  /* End: Turn off individual column border, margin, and padding when line numbers are showing */
  .highlight {
    position: relative;
    z-index: 0;
    padding: 0;
    margin:40px 0 10px 0;
    border-radius: 4px;
  .highlight > .chroma {
    position: static;
    z-index: 1;
    border-top-left-radius: 0px;
    border-top-right-radius: 0px;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    padding: 10px;
  .copy-code-button {
    position: absolute;
    z-index: 2;
    right: 0;
    top: -25px;
    font-size: 13px;
    font-weight: 400;
    line-height: 14px;
    letter-spacing: 0.5px;
    width: 65px;
    color: #ffffff;
    background-color: #000000;
    border: 0;
    border-radius: 4px;
    padding: 1px;
    font-size: 0.7em;
    line-height: 1.8;
    color: #fff;
    background-color: #777;
    min-width: 55px;
    padding: 1px;
    margin: 0 0 0 1px;
    cursor: pointer;
  .copy-code-button:active:hover {
    color: #222225;
    background-color: #b3b3b3;
    opacity: 0.8;
  .copyable-text-area {
    position: absolute;
    height: 0;
    z-index: -1;
    opacity: .01;
  .chroma [data-lang]:before {
    position: absolute;
    z-index: 0;
    top: -29px;
    left: 0;
    content: attr(data-lang);
    font-size: 13px;
    font-weight: 700;
    color: white;
    background-color: black;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    padding: 6px 6px 7px 6px;
    line-height: 14px;
    opacity: 0.6;
    position: absolute;
    letter-spacing: 0.5px;
    border: 1.25px solid #232326;
    margin: 0 0 0 1px;

#4 Display the category on top of the title #

On every post, the category needs to be shown and it should be a link. So if we click that category name, it should list all the posts from that category. Add the following code in the single.html file.

      {{ range .Params.categories }}
      <a href="{{ "/categories/" | relLangURL }}{{ . | urlize }}" class="category" data-accent="#cb4949" style="text-transform:uppercase; color: rgb(203, 73, 73); background: rgba(203, 73, 73, 0.15);">{{ . }}</a>
	{{ end }}

#5 Some more tweaks: #

There are many changes I have done to this blog, but those are small code blocks, you can find them anywhere on the internet. So I didn’t give those codes.

  • Custom style for display tags along with the date.
  • Added Google Analytics(GA4) into the header.
  • Added Adsense script.
  • Added Disqus comments script.
  • Home page with a limited number of posts and a banner image.
  • Custom Archive page to show all the posts.

Hosting with CloudFlare Pages #

My Jekyll was hosted on GitHub. But still I use CloudFlare for DNS. So I wanted to give a try with CloudFlare pages. Since it has more edge locations. I think this will increase the page loading speed. Also it has more features like

  • Automated deployment fro Private repo.
  • Rollback to any version
  • Deployments previews
  • Faster deployments
  • Analytics on the traffic
  • And more.