Operators in Liquid enable comparisons and logical operations within conditional statements. They're the building blocks that make your templates dynamic, allowing you to create conditions that determine what content gets displayed based on your data.

What are Liquid operators?

Operators are symbols and keywords that let you compare values and combine conditions in your Liquid templates. Understanding operators is essential before diving into filters and tags because they form the foundation of conditional logic, the decision-making layer that makes your notifications intelligent and context-aware.

There are three main categories of operators in Liquid:

  • Comparison operators evaluate relationships between values.
  • Logical operators combine multiple conditions.
  • Special operators handle specific scenarios like string containment.

Let's explore each category with practical notification examples.

Comparison operators

Comparison operators let you evaluate how two values relate to each other. These operators return either true or false, which you can use in conditional statements to control what content appears.

Equality operators

Equality operators check whether values are equal or not equal. These are the most basic comparisons you'll use:

  • Equal to (==): Returns true when both values are the same.
  • Not equal to (!=): Returns true when values are different.
Data
{
  "user": {
    "subscription_status": "active",
    "account_type": "premium"
  }
}
Template
{% if user.subscription_status == "active" %}
Your subscription is currently active.
{% endif %}

{% if user.account_type != "free" %}
Thank you for being a paid subscriber!
{% endif %}
Output
Your subscription is currently active.
Thank you for being a paid subscriber!

Relational operators

Relational operators compare numeric values or evaluate size relationships. These are particularly useful for checking thresholds, limits, and ranges:

  • Greater than (>): Returns true when the left value is larger than the right.
  • Less than (<): Returns true when the left value is smaller than the right.
  • Greater than or equal to (>=): Returns true when the left value is larger than or equal to the right.
  • Less than or equal to (<=): Returns true when the left value is smaller than or equal to the right.
Data
{
  "user": {
    "account_balance": 1500,
    "messages_sent": 4500,
    "message_limit": 5000
  }
}
Template
{% if user.account_balance > 1000 %}
✓ You qualify for our premium features!
{% endif %}

{% if user.messages_sent >= 4500 %}
⚠️ You're approaching your monthly message limit.
{% endif %}

{% if user.messages_sent < user.message_limit %}
You have {{ user.message_limit | minus: user.messages_sent }} messages remaining.
{% endif %}
Output
✓ You qualify for our premium features!
⚠️ You're approaching your monthly message limit.
You have 500 messages remaining.

Logical operators

Logical operators let you combine multiple conditions to create more sophisticated conditional logic.

The and operator

Use and when all conditions must be true:

Data
{
  "user": {
    "is_verified": true,
    "profile_complete": true,
    "payment_method": "visa"
  }
}
Template
{% if user.is_verified and user.profile_complete and user.payment_method %}
🎉 Your account is fully activated! You're ready to go.
{% else %}
Please complete your account setup to continue.
{% endif %}
Output
🎉 Your account is fully activated! You're ready to go.

The or operator

Use or when at least one condition must be true:

Data
{
  "user": {
    "plan": "premium",
    "total_spent": 850,
    "referral_count": 3
  }
}
Template
{% if user.plan == "premium" or user.total_spent > 1000 %}
You have access to priority support.
{% endif %}

{% if user.total_spent > 500 or user.referral_count >= 3 %}
You've unlocked access to our beta features!
{% endif %}
Output
You have access to priority support.
You've unlocked access to our beta features!

Combining logical operators

You can combine and and or operators, though be mindful that Liquid evaluates them left-to-right:

Data
{
  "order": {
    "items_count": 5,
    "total": 89.99,
    "is_first_order": true,
    "customer_tier": "gold"
  }
}
Template
{% if order.items_count >= 5 and order.total < 100 %}
You've unlocked bulk discount pricing!
{% endif %}

{% if order.is_first_order and order.total > 50 or order.customer_tier == "gold" %}
Free shipping applied to your order!
{% endif %}
Output
You've unlocked bulk discount pricing!
Free shipping applied to your order!

Special operators

Liquid provides special operators for common string and array operations.

The contains operator

The contains operator checks whether a string includes a substring or an array includes an element:

Data
{
  "user": {
    "email": "[email protected]",
    "features": [
      "api_access",
      "sso",
      "custom_domain"
    ],
    "tags": [
      "beta_tester",
      "early_adopter"
    ]
  }
}
Template
{% if user.email contains "@company.com" %}
Welcome, team member! You have access to internal tools.
{% endif %}

{% if user.features contains "api_access" %}
Your API key: xxx-xxx-xxx
{% endif %}

{% unless user.tags contains "premium" %}
Upgrade to premium for advanced features.
{% endunless %}
Output
Welcome, team member! You have access to internal tools.
Your API key: xxx-xxx-xxx
Upgrade to premium for advanced features.

Understanding truthy and falsy values

Liquid's truthiness rules determine how values are evaluated in conditional contexts. This is particularly important for notifications where you need to handle various data states correctly.

Falsy values in Liquid

Only two values are falsy in Liquid:

  • nil (or null)
  • false

Everything else is truthy, which can be surprising if you're coming from other programming languages:

  • Empty strings "" are truthy
  • Zero 0 is truthy
  • Empty arrays [] are truthy
Data
{
  "user": {
    "phone_number": null,
    "bio": "",
    "login_count": 0,
    "achievements": []
  }
}
Template
{% if user.phone_number %}
SMS: {{ user.phone_number }}
{% else %}
No phone number on file
{% endif %}

{% if user.bio %}
Bio: {{ user.bio }}
(Note: Empty strings are truthy!)
{% endif %}

{% if user.login_count %}
Login count: {{ user.login_count }}
(Note: Zero is truthy!)
{% endif %}

{% if user.achievements %}
(Note: Empty arrays are truthy!)
Achievements exist: {{ user.achievements.size }} achievements
{% endif %}
Output
No phone number on file

Bio:
(Note: Empty strings are truthy!)

Login count: 0
(Note: Zero is truthy!)

(Note: Empty arrays are truthy!)
Achievements exist: 0 achievements

Defensive checks

Because of these truthiness rules, it's important to check explicitly for the conditions you care about:

Data
{
  "user": {
    "bio": "",
    "age": 0,
    "notifications": []
  }
}
Template
{# Check for nil explicitly #}
{% if user.phone_number != nil %}
SMS enabled
{% endif %}

{# Check for empty strings #}
{% if user.bio != "" %}
Bio: {{ user.bio }}
{% else %}
No bio provided
{% endif %}

{# Check for zero #}
{% if user.age > 0 %}
Age: {{ user.age }}
{% endif %}

{# Check array size #}
{% if user.notifications.size > 0 %}
You have notifications
{% else %}
No new notifications
{% endif %}
Output
No bio provided
No new notifications

The unless tag with operators

The unless tag is the inverse of if—it executes when a condition is false:

Data
{
  "user": {
    "email_verified": false,
    "age": 16,
    "country": "US"
  }
}
Template
{% unless user.email_verified %}
⚠️ Please verify your email address to continue.
{% endunless %}

{% unless user.age >= 18 %}
This content is restricted to users 18 and older.
{% endunless %}

{% unless user.country == "US" %}
International shipping rates apply.
{% endunless %}
Output
⚠️ Please verify your email address to continue.
This content is restricted to users 18 and older.

Putting operators together

Operators work together to create sophisticated conditional logic in your templates:

Data
{
  "user": {
    "trial_days_remaining": 2,
    "has_payment_method": false,
    "total_users_invited": 5,
    "conversion_rate": 0.15
  }
}
Template
{% if user.trial_days_remaining > 0 and user.trial_days_remaining <= 3 %}
⏰ Your trial ends in {{ user.trial_days_remaining }} days.

{% unless user.has_payment_method %}
Add a payment method to avoid service interruption.
{% endunless %}
{% endif %}

{% if user.total_users_invited >= 5 and user.conversion_rate > 0.1 %}
🌟 Great referral performance! You've earned a bonus.
{% endif %}
Output
⏰ Your trial ends in 2 days.

Add a payment method to avoid service interruption.

🌟 Great referral performance! You've earned a bonus.

Understanding operators is fundamental to writing effective Liquid templates. They allow you to create dynamic, context-aware content that responds intelligently to your data. As you move into filters and tags in the next chapters, you'll use these operators extensively to build sophisticated notification logic.