Detected country: US
logo
‌
‌
‌
logo

Powered by

  • Home
  • Compensation Planning
  • Columns and Formulas
  • Writing formulas with Handlebars

Writing formulas with Handlebars

5min read

Share

How formulas work in Pave

Formulas let you create calculated columns that derive values from other data in the cycle. You write them using a templating language called Handlebars. If you've written spreadsheet formulas, the concepts are the same: reference a cell (here, a column), apply a function, get a result.

Every formula goes inside double curly braces: {{ }}. Inside the braces, you reference employee data with columns.fieldName and call built-in functions (called helpers) by name.

Your first formula

To output an employee's base pay, just reference it:

{{columns.basePay}}

To multiply base pay by 5%:

{{multiply columns.basePay 0.05}}

To nest one function inside another, wrap the inner one in parentheses:

{{round (divide columns.annualBonusCash columns.basePay) 2}}

This divides bonus by base pay, then rounds to 2 decimal places.

That's the entire syntax. The rest of this guide covers what helpers are available and how to combine them.

If/else: choosing between values

This is the most commonly used pattern. Use #if to branch based on a condition.

Simple if/else:

{{#if columns.isPromotion}}
  {{multiply columns.newBase 0.10}}
{{else}}
  0
{{/if}}

Multiple branches (if / else if):

{{#if (eq columns.level "P1")}}0.10
{{else if (eq columns.level "P2")}}0.15
{{else if (eq columns.level "P3")}}0.20
{{else}}0
{{/if}}

Inline if (one-line, inside another expression):

{{add columns.salary (inlineIf columns.eligible columns.bonus 0)}}

Unless (opposite of if):

{{#unless columns.isExcluded}}
  {{columns.salaryRaise}}
{{/unless}}

Every {{#if}} must end with {{/if}}. Every {{#unless}} must end with {{/unless}}.

Comparison helpers

Use these inside #if to compare values. They return true or false.

HelperMeaningExample
eqEquals(eq columns.country "Japan")
neNot equals(ne columns.variablePay 0)
gtGreater than(gt columns.tenureDays 1095)
gteGreater than or equal(gte columns.daysInRole 365)
ltLess than(lt columns.startDate '2025-01-01')
lteLess than or equal(lte columns.compaRatio 1.0)

Logical helpers

Combine multiple conditions.

HelperMeaningExample
andTrue if all are true(and (eq columns.dept "Sales") (gt columns.tenure 1))
orTrue if any are true(or (eq columns.level "P1") (eq columns.level "P2"))
notFlips true to false(not columns.isPromotion)
includesTrue if text/list contains a value(includes columns.tags "Sales")
isNullOrUndefinedTrue if the field is empty(isNullOrUndefined columns.bonusOverride)

Math helpers

HelperWhat it doesExample
addAdds numbers{{add columns.basePay columns.variablePay}}
subtractSubtracts{{subtract columns.newBase columns.basePay}}
multiplyMultiplies{{multiply columns.basePay 0.05}}
divideDivides{{divide columns.basePay 12}}
roundRounds to N decimals{{round columns.value 2}}
ceilRounds up{{ceil (divide columns.shares 100)}}
floorRounds down{{floor (divide columns.shares 100)}}
maxLargest of the values{{max columns.a columns.b}}
minSmallest of the values{{min columns.a columns.b}}
absAbsolute value{{abs (subtract columns.a columns.b)}}
modRemainder after division{{mod columns.x 2}}
powerRaises to a power{{power columns.x 2}}

Rounding to specific increments

The round helper rounds to decimal places. To round to the nearest $100 or $1,000, combine round with multiply and divide:

Nearest $100:    {{multiply (round (divide columns.newBase 100)) 100}}
Nearest $1,000:  {{multiply (round (divide columns.newBase 1000)) 1000}}
Nearest cent:    {{divide (round (multiply columns.newBase 100)) 100}}

Date helpers

HelperWhat it doesExample
dayDiffDays between two dates{{dayDiff '2025-01-01' columns.startDate}}
monthDiffFull months between two dates{{monthDiff columns.startDate '2026-02-01'}}
durationHuman-readable tenure{{duration columns.startDate '2026-02-01'}}
dateAddAdd days to a date{{dateAdd columns.startDate 90 'days'}}
dateFormatFormat a date for display{{dateFormat columns.startDate 'MM/dd/yyyy'}}

Text helpers

HelperWhat it doesExample
concatJoins strings{{concat columns.firstName " " columns.lastName}}
splitSplits text; optional index returns one piece{{split columns.fullName ' ' 0}} (first name)
substringExtracts part of a string{{substring columns.level 0 1}} (first character)
replaceReplaces text{{replace columns.salary ',' ''}} (strip commas)
formatCurrencyFormats a number as currency{{formatCurrency columns.basePay 'USD'}}
toNumberConverts text to a number{{toNumber columns.salaryFromUpload}}
toStringConverts a number to text{{toString columns.level}}
toUpperUppercases text{{toUpper columns.country}}
toLowerLowercases text{{toLower columns.email}}
titleCaseCapitalizes each word{{titleCase columns.name}}

Handling empty values

HelperWhat it doesExample
coalesceReturns the first non-empty value{{coalesce columns.override columns.default}}
isNullOrUndefinedTrue if a field is empty (use inside #if){{#if (not (isNullOrUndefined columns.bonus))}}...{{/if}}

Saving intermediate values with setVar

When your formula needs the same value in multiple places, or when a calculation has several steps that are hard to follow as a single nested expression, setVar lets you break it into named pieces. You assign an intermediate result to a name, then reference that name later in the formula as if it were a column. This is especially useful for multi-step calculations like proration (compute daily pay, compute days worked, then multiply), formulas that reuse the same sub-expression (compute a base amount once, then use it in both a percentage and a dollar calculation), and lookup-driven logic where you store a converted value (like an FX-adjusted salary) before applying further math to it. Without setVar, these formulas would require deeply nested expressions that are difficult to read and debug.

For long calculations, save partial results into a named variable to keep things readable.

{{setVar 'dailyPay' (divide columns.basePay 365)}}
{{setVar 'daysWorked' (dayDiff columns.startDate '2025-12-31')}}
{{multiply dailyPay daysWorked}}

Working with lookup tables (setMapVar / getMapVal)

Some fields contain structured data (like band values with min/target/max). Use getMapVal to pull one value out.

{{getMapVal columns.equityBandRawValues 'target'}}

You can also create your own lookup tables inline. This is commonly used for FX rates or level-to-tier mappings:

{{setMapVar 'fxRates' '{"USD":1,"EUR":1.08,"GBP":1.27}'}}
{{multiply columns.basePay (getMapVal fxRates columns.currency)}}

Controlling whitespace

Formulas that span multiple lines can produce unexpected whitespace in the output. Add ~ inside the braces to strip whitespace from that side:

{{#if columns.isPromotion}}
  {{~columns.newBase~}}
{{else}}
  {{~columns.basePay~}}
{{/if}}

The ~ strips whitespace from whichever side it's on. {{~value~}} strips both sides. {{value~}} strips only the right side.

Common recipes

These are the most-used patterns across Pave customers.

On-target earnings:

{{add columns.basePay columns.variablePay}}

Percent change between current and new total cash:

{{divide (subtract columns.newTotalAnnualCash columns.currentTotalAnnualCash) columns.currentTotalAnnualCash}}

Pro-rated bonus by start date:

{{multiply columns.annualBonusCash (divide (dayDiff columns.startDate '2025-12-31') 365)}}

Cap a raise at zero (no negative raises):

{{max (subtract columns.newBase columns.basePay) 0}}

Compa-ratio:

{{divide columns.basePay (getMapVal columns.salaryImpact 'bandMid')}}

Monthly salary from annual:

{{divide columns.basePay 12}}

Hourly rate (2,080 working hours/year):

{{divide columns.basePay 2080}}

First name (for reward letters):

{{split columns.fullName ' ' 0}}

Multi-step calculation:

{{setVar 'increase' (multiply columns.basePay 0.025)}}
{{setVar 'days' (dayDiff columns.startDate columns.effectiveDate)}}
{{divide (multiply increase days) 365}}

Tips

  • Use the live preview in the column editor to test your formula against real employee data before saving.
  • Strings need quotes ("Sales" or 'Sales'). Numbers don't.
  • Whitespace and line breaks inside {{ }} don't affect the result. Use them to keep complex formulas readable.
  • Combine operations by nesting with parentheses: {{multiply (add a b) c}}.

Share