Skip to content

Boolean Expressions Guide

Boolean expressions allow you to evaluate complex logical conditions directly within placeholders. Combine variables with operators to create dynamic, conditional content without using separate {{#if}} blocks.

Table of Contents

Quick Start

Wrap any boolean expression in parentheses within a placeholder:

Template:

Eligible: {{(Age >= 18)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Age"] = 25
};

JSON Data:

{
  "Age": 25
}

Output:

Eligible: True

Expression Syntax

Basic Rules

  1. Expressions must start with ( - This distinguishes them from simple variables
  2. Expressions must end with ) - Properly close the parentheses
  3. Operators are case-insensitive - and, AND, And all work
  4. Spaces are optional - (var1 and var2) equals (var1and var2)

Expression vs. Simple Variable

Simple Variable (no evaluation):

Status: {{IsActive}}

Expression (evaluated):

Status: {{(IsActive)}}

Complex Expression:

Status: {{(IsActive and IsVerified)}}

Logical Operators

AND Operator

Returns true only if both operands are true.

Syntax: and

Truth Table:

Left Right Result
true true true
true false false
false true false
false false false

Template:

Access granted: {{(IsActive and IsVerified)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["IsActive"] = true,
    ["IsVerified"] = true
};

JSON Data:

{
  "IsActive": true,
  "IsVerified": true
}

Output:

Access granted: True

OR Operator

Returns true if at least one operand is true.

Syntax: or

Truth Table:

Left Right Result
true true true
true false true
false true true
false false false

Template:

Can proceed: {{(HasPermissionA or HasPermissionB)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["HasPermissionA"] = false,
    ["HasPermissionB"] = true
};

JSON Data:

{
  "HasPermissionA": false,
  "HasPermissionB": true
}

Output:

Can proceed: True

NOT Operator

Returns the opposite of the operand.

Syntax: not

Truth Table:

Value Result
true false
false true

Template:

Account locked: {{(not IsActive)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["IsActive"] = false
};

JSON Data:

{
  "IsActive": false
}

Output:

Account locked: True

Comparison Operators

Equality (== or =)

Checks if two values are equal. Both == and = are supported.

Template:

Status is active: {{(Status == "active")}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Status"] = "active"
};

JSON Data:

{
  "Status": "active"
}

Output:

Status is active: True

Inequality (!=)

Checks if two values are not equal.

Template:

Status is not pending: {{(Status != "pending")}}

Data:

{
  "Status": "active"
}

Output:

Status is not pending: True

Greater Than (>)

Checks if left value is greater than right value.

Template:

Has items: {{(Count > 0)}}

Data:

{
  "Count": 5
}

Output:

Has items: True

Greater Than or Equal (>=)

Checks if left value is greater than or equal to right value.

Template:

Is adult: {{(Age >= 18)}}

Data:

{
  "Age": 18
}

Output:

Is adult: True

Less Than (<)

Checks if left value is less than right value.

Template:

Under budget: {{(Spent < Budget)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Spent"] = 800,
    ["Budget"] = 1000
};

JSON Data:

{
  "Spent": 800,
  "Budget": 1000
}

Output:

Under budget: True

Less Than or Equal (<=)

Checks if left value is less than or equal to right value.

Template:

At or under limit: {{(Count <= MaxCount)}}

Data:

{
  "Count": 10,
  "MaxCount": 10
}

Output:

At or under limit: True

Membership, String, and Existence Operators

Membership (in)

Checks whether a value is a member of a collection. The right side can be a collection variable, a quoted list literal, or a comma-separated string.

Template:

Recognized role: {{(Role in Roles)}}
Can publish: {{(Role in ("Admin", "Editor")):yesno}}

Data:

{
  "Role": "Editor",
  "Roles": ["Admin", "Editor", "Viewer"]
}

Output:

Recognized role: True
Can publish: Yes

Negate with not: {{(not Role in Roles)}}.

String Checks (contains, startswith, endswith)

Template:

Priority: {{(Description contains "urgent"):yesno}}

Data:

{
  "Description": "This order is urgent"
}

Output:

Priority: Yes

These comparisons are case-sensitive, like = and ==.

Existence (exists, is empty, is not empty)

exists checks that a variable is present regardless of its value; is empty / is not empty check whether a value is missing, null, blank, or an empty collection.

Template:

Notes provided: {{(Notes exists):yesno}}
Notes empty: {{(Notes is empty):yesno}}

Data:

{
  "Notes": ""
}

Output:

Notes provided: Yes
Notes empty: Yes

Reserved Words and Literal Quoting

The operator keywords are reserved words. The following names are always interpreted as operators, never as variable names or bareword text:

and, or, not, in, contains, startswith, endswith, exists, is, empty

Because of this, string literals must be quoted. Write = "empty", not = empty:

Status is missing: {{(Category = "empty"):yesno}}   ← compares against the text "empty"

If you leave a reserved word unquoted (for example {{(Category = empty)}}), Templify reads empty as the reserved keyword rather than as the literal text empty, and the expression will not evaluate as you intended. Always quote string literals that could collide with a reserved word.

In inline {{(...)}} expressions, both sides of a comparison are resolved as variables-or-literals. In {{(A = B)}}, both A and B are looked up in your data; the comparison succeeds when the two resolved values are equal. Quote a side ({{(A = "B")}}) when you mean the literal text rather than a variable lookup.

Combining with Format Specifiers

The real power comes from combining expressions with format specifiers for human-readable output.

Basic Combination

Template:

Eligible: {{(Age >= 18):yesno}}

Data:

{
  "Age": 20
}

Output:

Eligible: Yes

Complex Expression with Checkbox

Template:

Access: {{(IsActive and IsVerified):checkbox}}

Data:

{
  "IsActive": true,
  "IsVerified": true
}

Output:

Access: ☑

Multiple Conditions with Checkmark

Template:

Qualified: {{(Age >= 18 and HasLicense):checkmark}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Age"] = 25,
    ["HasLicense"] = true
};

JSON Data:

{
  "Age": 25,
  "HasLicense": true
}

Output:

Qualified: ✓

OR Logic with Format

Template:

Can edit: {{(IsOwner or IsAdmin):enabled}}

Data:

{
  "IsOwner": false,
  "IsAdmin": true
}

Output:

Can edit: Enabled

Advanced Usage

Nested Expressions

Use nested parentheses to control evaluation order.

Template:

Result: {{((var1 or var2) and var3)}}

C# Data:

var data = new Dictionary<string, object>
{
    ["var1"] = true,
    ["var2"] = false,
    ["var3"] = true
};

JSON Data:

{
  "var1": true,
  "var2": false,
  "var3": true
}

Output:

Result: True

Evaluation: 1. (var1 or var2)(true or false)true 2. (true and var3)(true and true)true

Complex Nested Expressions

Template:

Approved: {{((Age >= 18) and (HasLicense or HasPermit)):yesno}}

Data:

{
  "Age": 20,
  "HasLicense": false,
  "HasPermit": true
}

Output:

Approved: Yes

With Nested Properties

Template:

User active: {{(User.IsActive):checkbox}}
Profile complete: {{(User.Profile.IsComplete):yesno}}

C# Data:

var data = new Dictionary<string, object>
{
    ["User"] = new
    {
        IsActive = true,
        Profile = new
        {
            IsComplete = false
        }
    }
};

JSON Data:

{
  "User": {
    "IsActive": true,
    "Profile": {
      "IsComplete": false
    }
  }
}

Output:

User active: ☑
Profile complete: No

In Loops

Use expressions within loop bodies for dynamic row-level logic.

Template:

{{#foreach Employees}}
- {{Name}}: {{(IsActive and HasCompletedTraining):checkbox}}
{{/foreach}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Employees"] = new[]
    {
        new { Name = "Alice", IsActive = true, HasCompletedTraining = true },
        new { Name = "Bob", IsActive = true, HasCompletedTraining = false },
        new { Name = "Carol", IsActive = false, HasCompletedTraining = true }
    }
};

JSON Data:

{
  "Employees": [
    { "Name": "Alice", "IsActive": true, "HasCompletedTraining": true },
    { "Name": "Bob", "IsActive": true, "HasCompletedTraining": false },
    { "Name": "Carol", "IsActive": false, "HasCompletedTraining": true }
  ]
}

Output:

- Alice: ☑
- Bob: ☐
- Carol: ☐

Comparing Numbers from Different Sources

Template:

Over threshold: {{(CurrentValue > Threshold):yesno}}
Within budget: {{(Spent <= Budget):yesno}}

Data:

{
  "CurrentValue": 150,
  "Threshold": 100,
  "Spent": 800,
  "Budget": 1000
}

Output:

Over threshold: Yes
Within budget: Yes

String Comparisons

Template:

Is pending: {{(Status == "pending"):yesno}}
Not cancelled: {{(Status != "cancelled"):checkmark}}

Data:

{
  "Status": "pending"
}

Output:

Is pending: Yes
Not cancelled: ✓

Best Practices

1. Use Expressions for Simple Logic

For inline boolean checks, expressions are cleaner than separate conditionals.

Good (concise):

Status: {{(IsActive and IsVerified):checkbox}}

Less Good (verbose):

{{#if IsActive}}
{{#if IsVerified}}
Status: ☑
{{/if}}
{{/if}}
{{#if (not IsActive)}}
Status: ☐
{{/if}}
{{#if (not IsVerified)}}
Status: ☐
{{/if}}

2. Use Conditionals for Complex Content

When you need to show/hide entire blocks of content, use {{#if}} instead.

Good:

{{#if IsActive}}
Account Details:
- Name: {{Name}}
- Email: {{Email}}
- Joined: {{JoinDate}}
{{/if}}

Not Recommended:

Account Details: {{(IsActive):yesno}}

3. Keep Expressions Readable

Break complex logic into multiple lines or use separate variables.

Good:

Qualified: {{(Age >= 18 and HasLicense):yesno}}

Less Readable:

Status: {{(((Age >= 18) and (HasLicense or HasPermit)) and (not IsBlacklisted) and (CreditScore > 600)):checkmark}}

Better Approach:

// In your C# code:
var data = new Dictionary<string, object>
{
    ["Age"] = 25,
    ["HasLicense"] = true,
    ["HasPermit"] = false,
    ["IsBlacklisted"] = false,
    ["CreditScore"] = 650,
    ["IsQualified"] = (25 >= 18) && (true || false) && !false && (650 > 600)
};

Template:

Qualified: {{IsQualified:checkmark}}

4. Use Meaningful Variable Names

Clear variable names make expressions self-documenting.

Good:

Eligible: {{(HasValidLicense and IsInsured):yesno}}

Less Clear:

Eligible: {{(var1 and var2):yesno}}

5. Consider Evaluation Cost

Complex expressions are evaluated every time they're encountered. For frequently used values, pre-calculate in your data.

Efficient:

var data = new Dictionary<string, object>
{
    ["IsEligible"] = (age >= 18 && hasLicense)
};

Template:

Eligible: {{IsEligible:yesno}}

Real-World Examples

Approval Workflow Document

Template:

Approval Request
================

Request Details:
- Submitted by: {{Requester.Name}}
- Amount: ${{Amount}}
- Date: {{SubmittedDate}}

Approval Status:
- Manager Approval: {{(ManagerApproved):checkbox}}
- Director Approval: {{(DirectorApproved):checkbox}}
- CFO Approval Required: {{(Amount > 10000):yesno}}
- CFO Approved: {{(CFOApproved or Amount <= 10000):checkbox}}

Final Status: {{((ManagerApproved and DirectorApproved) and (CFOApproved or Amount <= 10000)):checkmark}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Requester"] = new { Name = "John Smith" },
    ["Amount"] = 15000,
    ["SubmittedDate"] = "2025-01-15",
    ["ManagerApproved"] = true,
    ["DirectorApproved"] = true,
    ["CFOApproved"] = true
};

JSON Data:

{
  "Requester": { "Name": "John Smith" },
  "Amount": 15000,
  "SubmittedDate": "2025-01-15",
  "ManagerApproved": true,
  "DirectorApproved": true,
  "CFOApproved": true
}

Employee Benefits Eligibility

Template:

Benefits Eligibility Report
===========================

Employee: {{Employee.Name}}
Hire Date: {{Employee.HireDate}}
Employment Status: {{Employee.Status}}

Eligibility:
- Health Insurance: {{(Employee.Status == "Full-Time" and Employee.TenureMonths >= 1):yesno}}
- 401(k) Match: {{(Employee.Status == "Full-Time" and Employee.TenureMonths >= 6):yesno}}
- Stock Options: {{(Employee.Status == "Full-Time" and Employee.TenureMonths >= 12):yesno}}
- Gym Membership: {{(Employee.Status != "Contractor"):yesno}}

Data:

{
  "Employee": {
    "Name": "Sarah Johnson",
    "HireDate": "2024-08-15",
    "Status": "Full-Time",
    "TenureMonths": 5
  }
}

System Requirements Check

Template:

System Requirements Check
=========================

{{#foreach Requirements}}
{{Name}}: {{(IsMet):checkmark}}
{{/foreach}}

Overall Status: {{((CPUMeetsReq and MemoryMeetsReq) and DiskMeetsReq):active}}
Installation Ready: {{(((CPUMeetsReq and MemoryMeetsReq) and DiskMeetsReq) and OSSupported):yesno}}

C# Data:

var data = new Dictionary<string, object>
{
    ["Requirements"] = new[]
    {
        new { Name = "CPU: 2GHz or faster", IsMet = true },
        new { Name = "RAM: 8GB minimum", IsMet = true },
        new { Name = "Disk: 50GB free space", IsMet = false },
        new { Name = "OS: Windows 10 or later", IsMet = true }
    },
    ["CPUMeetsReq"] = true,
    ["MemoryMeetsReq"] = true,
    ["DiskMeetsReq"] = false,
    ["OSSupported"] = true
};

JSON Data:

{
  "Requirements": [
    { "Name": "CPU: 2GHz or faster", "IsMet": true },
    { "Name": "RAM: 8GB minimum", "IsMet": true },
    { "Name": "Disk: 50GB free space", "IsMet": false },
    { "Name": "OS: Windows 10 or later", "IsMet": true }
  ],
  "CPUMeetsReq": true,
  "MemoryMeetsReq": true,
  "DiskMeetsReq": false,
  "OSSupported": true
}

Project Risk Assessment

Template:

Project Risk Assessment
=======================

Project: {{Project.Name}}

Risk Indicators:
- Behind Schedule: {{(Project.DaysOverdue > 0):yesno}}
- Over Budget: {{(Project.SpentPercentage > 100):yesno}}
- Low Team Morale: {{(Project.MoraleScore < 3):yesno}}
- High Complexity: {{(Project.ComplexityScore >= 8):yesno}}

Risk Level:
- Low Risk: {{((Project.DaysOverdue <= 0) and (Project.SpentPercentage <= 100)):checkbox}}
- Medium Risk: {{((Project.DaysOverdue > 0 or Project.SpentPercentage > 100) and Project.MoraleScore >= 3):checkbox}}
- High Risk: {{((Project.DaysOverdue > 5 or Project.SpentPercentage > 120) or Project.MoraleScore < 3):checkbox}}

Data:

{
  "Project": {
    "Name": "Website Redesign",
    "DaysOverdue": 3,
    "SpentPercentage": 95,
    "MoraleScore": 4,
    "ComplexityScore": 7
  }
}

Operator Precedence

Expressions are evaluated with standard operator precedence:

  1. Parentheses () - Highest priority
  2. NOT not
  3. Comparison >, >=, <, <=, =, ==, !=, in, contains, startswith, endswith
  4. AND and
  5. OR or - Lowest priority

and always binds tighter than or. Use parentheses to override the default grouping.

exists, is empty, and is not empty are postfix operators — they attach directly to the variable that precedes them (e.g. Notes is empty), so they behave like a comparison result and combine with and/or the same way.

Examples

Expression: var1 or var2 and var3 Evaluation: var1 or (var2 and var3) ← AND binds tighter

Expression: (var1 or var2) and var3 Evaluation: Parentheses force OR first

Expression: not var1 and var2 Evaluation: (not var1) and var2 ← NOT binds tightest

Summary

Boolean expressions enable powerful inline logic in your templates:

  • ✅ Logical operators: and, or, not
  • ✅ Comparison operators: =, ==, !=, >, >=, <, <=
  • ✅ Membership, string, and existence operators: in, contains, startswith, endswith, exists, is empty, is not empty
  • ✅ Nested expressions with parentheses
  • ✅ Combine with format specifiers for readable output
  • ✅ Works with nested properties and arrays
  • ✅ Use in loops and conditionals
  • ✅ Same data works with C# Dictionaries or JSON
  • ✅ Case-insensitive operators

For more information, see: - Format Specifiers Guide - Format boolean output - API Reference - Complete API documentation - Examples - More code examples - FAQ - Common questions