Liquid is the templating language used by Jekyll. This guide covers the essential Liquid syntax for building dynamic Jekyll sites. Liquid was created by Shopify and is one of the most widely used template languages in the Ruby ecosystem. Understanding Liquid is essential for anyone working with Jekyll, as it powers everything from simple variable output to complex page layouts.

How Liquid Works

Liquid uses two types of delimiters:

  • Output tags {{ }}: Output the value of a variable or expression
  • Logic tags {% %}: Execute logic like conditionals, loops, and includes

These delimiters can be used anywhere in your Jekyll markdown or HTML files.

Reference

  • https://jekyllrb.com/docs/step-by-step/02-liquid/

Tags

  • https://jekyllrb.com/docs/liquid/tags/

Adding - after {% or before %} removes whitespace around the tag (e.g., {%- if ... -%}).

page variable

The whitespace control with - is particularly useful when generating HTML, as extra whitespace from Liquid tags can affect your page layout.

syntax highlight

def foo
  puts 'foo'
end
def foo():
  print('foo')

Supported languages include ruby, python, javascript, html, css, bash, java, json, yaml, and many more. You can also add line numbers with linenos:

1
2
3
def hello
  puts 'hello world'
end
  • Link by Tag: provides link validation on build time. if front matter not exists, the error below occurs.
    • Liquid Exception: Could not find document ‘_posts/tools/jekyll/2023-12-05-jekyll-seo.md’ in tag ‘link’. Make sure the document exists and the path is correct. in /github/workspace/_posts/tools/jekyll/2023-12-04-jekyll-liquid.md
  • [Link by variables] % link _posts/tools/jekyll/2023-12-05-jekyll-seo.md %: this way is not supported on Github Pages.
  • Link by post_url: able to access other directory’s post with post name

The link tag is preferred over hardcoded URLs because it validates that the linked page exists at build time. If you rename or delete a post, the build will fail with a clear error message rather than silently creating a broken link.

Filter

Filters transform the output of a Liquid variable. They are applied using the pipe | character.

  • Capitalize
  • default value
  • 29 Nov 2023

Commonly Used Filters

Filter Description Example
capitalize Capitalizes the first letter {{ "hello" | capitalize }} → Hello
downcase Converts to lowercase {{ "HELLO" | downcase }} → hello
upcase Converts to uppercase {{ "hello" | upcase }} → HELLO
strip_html Removes HTML tags {{ "<p>text</p>" | strip_html }} → text
truncate Truncates to N characters {{ "long text" | truncate: 4 }} → long…
date Formats a date {{ page.date | date: "%Y-%m-%d" }}
default Default value if nil/empty {{ var | default: "N/A" }}
jsonify Converts to JSON {{ site.data.items | jsonify }}
where Filters an array {{ site.posts | where: "draft", false }}
sort Sorts an array {{ site.posts | sort: "title" }}

if

page variable

You can also use elsif and else for more complex conditions:

{% if page.category == "tutorial" %}
  This is a tutorial
{% elsif page.category == "blog" %}
  This is a blog post
{% else %}
  This is other content
{% endif %}

Other comparison operators include ==, !=, >, <, >=, <=, contains, and, or.

for

The for loop also supports useful features like limit, offset, and reversed:

{% for post in site.posts limit:5 %}
  {{ post.title }}
{% endfor %}

{% for post in site.posts offset:2 limit:3 %}
  {{ post.title }}
{% endfor %}

Inside a for loop, you can access forloop.index (1-based), forloop.index0 (0-based), forloop.first, and forloop.last to control rendering logic.

assign

You can create and set variables using assign:

{% assign my_variable = "Hello World" %}
{% assign post_count = site.posts | size %}

capture

The capture tag lets you store a block of content in a variable:

{% capture full_url %}{{ site.url }}{{ page.url }}{% endcapture %}

include

You can also pass parameters to includes:

{% include alert.html type="warning" message="Be careful!" %}

Inside alert.html, access the parameters with {{ include.type }} and {{ include.message }}.

Common Pitfalls

  1. Raw tag for Liquid in code blocks: When showing Liquid code examples, wrap them in raw/endraw tags to prevent Jekyll from processing them.
  2. Variable scope: Variables defined inside for loops or if blocks are accessible outside them in Liquid, unlike most programming languages.
  3. Nil checking: Use an if check or the default filter to handle nil values gracefully.