celigo/ai13 files

Writing Handlebars

Write Handlebars template expressions for Celigo integrations -- dynamic values in mappings, HTTP bodies, SQL queries, URIs, and filters. Use when building any resource configuration that needs computed, conditional, or formatted field values.

Specification
Skill ID
celigo/ai/writing-handlebars
Publisher
celigo
Repository
ai
Installs
0
Files
13
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

celigo/ai/writing-handlebarsInstalls these files
  • SKILL.md
  • references/helpers/array.md
  • references/helpers/auth.md
  • references/helpers/block-helpers.md
  • references/helpers/date.md
  • references/helpers/encoding.md
  • references/helpers/format.md
  • references/helpers/helper-index.md
  • references/helpers/math.md
  • references/helpers/regex.md
  • references/helpers/string.md
  • references/helpers/syntax-and-recipes.md
  • references/helpers/type-logic.md

What this skill tells the agent

<!-- TIER:1 -->

Writing Handlebars Expressions

Handlebars is Celigo's template language for embedding dynamic values into resource configurations. Any string field that the platform evaluates at runtime can contain Handlebars expressions.

Concerns when writing Handlebars:

  • Context -- where the expression runs determines what data is available and how output is treated
  • Braces -- double {{ }} vs triple {{{ }}} controls output escaping
  • Field access -- record. prefix in all contexts (AFE 2.0), @root for job/settings/connection, bracket notation for special characters
  • Helpers -- 79 custom helpers for math, string manipulation, dates, encoding, regex, and more
  • Block helpers -- #each, #if, #compare, #with for iteration and conditional logic
  • Date/time -- moment.js format tokens with timezone support

Used across exports, imports, mappings, output filters, and APIs.

Where Handlebars Are Used

Mapping extracts

In import mappings[].extract fields, Handlebars concatenates, transforms, or conditionally selects values. The context is the current record.

HTTP request templates

Export and import http blocks use Handlebars in relativeURI, body, headers, and postBody. Triple braces are essential to avoid HTML encoding of query parameters and JSON.

RDBMS SQL queries

SQL queries in rdbms.query use Handlebars with the mandatory record. prefix. Triple braces prevent encoding of SQL-significant characters like commas and quotes. For full SQL patterns (MERGE, upsert, bulk operations, dialect differences), see writing-sql.

Output filters

Expression-based filters on exports use Handlebars to evaluate whether a record passes through or gets skipped.

File paths and names

Dynamic file names in FTP/S3 exports and imports use Handlebars for timestamps and record-derived values.

Delta tokens

Platform-injected variables like {{{lastExportDateTime}}} provide the last successful export timestamp for incremental syncs. These are not record fields -- the platform injects them at runtime into the export's HTTP/query context only.

Quick Reference

Context Decision Matrix (AFE 2.0)

All contexts use record. prefix to access the current record's fields (AFE 2.0). Do NOT use bare field names, data.field, or data.0.field -- those are deprecated AFE 1.0 patterns. Exception: Mapper 1.0 (Salesforce/NetSuite) uses bare field names without record. prefix.

WhereSyntaxData prefixExample
Mapping extract{{ }} (double)record.{{record.firstName}}
HTTP relative URI{{{ }}} (triple)record.{{{record.orderId}}} in URI
HTTP body / postBody{{{ }}} (triple)record.{{{record.orderId}}} in JSON body
SQL query (RDBMS){{{ }}} (triple)record.{{{record.email}}} in WHERE clause
Output filter{{ }} (double)record.{{record.status}}
Delta URI parameter{{{ }}} (triple)(platform-injected){{{lastExportDateTime}}}

Additional context objects available via @root:

ObjectDescription
recordCurrent record being processed
jobCurrent job metadata
settingsIntegration/flow settings
connectionConnection object (for auth headers)

When one-to-many grouping is configured, the data shape changes to batch_of_records -- iterate with {{#each batch_of_records}} to access individual records.

Key Syntax

  • `{{{triple-braces}}}` -- raw output, no escaping. Use for URIs, SQL, JSON bodies, file paths -- anywhere commas, quotes, or ampersands matter. In RDBMS, triple braces output the raw value (value); double braces wrap in single quotes ('value'). Prefer triple and add literal quotes explicitly where needed.
  • `{{double-braces}}` -- context-dependent formatting. In RDBMS adds single quotes around the value. In URLs, URL-encodes. Use triple braces for explicit control.
  • Always use `record.` prefix (AFE 2.0) -- {{{record.fieldName}}} in all contexts, never bare {{{fieldName}}} or {{{data.fieldName}}} (AFE 1.0). Nested fields: {{{record.properties.email}}}.
  • Exception: Mapper 1.0 (Salesforce/NetSuite) -- uses bare field names without record. prefix. This is the only context where bare field references are correct.

Related Skills

  • configuring-exports > Quick Reference -- export adaptor types, delta sync setup, output filters
  • configuring-imports > Quick Reference -- import adaptor types, operation modes, mapping systems
  • writing-mappings > Quick Reference -- Mapper 2.0 fields, lookups, conditional mappings

<!-- TIER:2 -->

Syntax Fundamentals

Braces

SyntaxBehaviorWhen to use
{{ }}Context-dependent formatting -- RDBMS wraps value in single quotes ('value'), URLs get URL-encodedUse only when auto-formatting is desired
{{{ }}}Raw output, no escaping or wrappingPrefer everywhere -- SQL, JSON bodies, URIs, file paths. Add literal quotes yourself where needed
{{{{ }}}}Raw block -- contents treated as literal stringEscaping Handlebars syntax itself

Field access

PatternMeaning
record.fieldNameStandard field reference -- all contexts (AFE 2.0)
record.nested.fieldDot-notation for nested objects
record.[Field With Spaces]Bracket notation for special characters in field names
record.items.[0].nameArray index access
@root.fieldNameRoot context -- escape nested #each scope
../fieldNameParent context -- one level up from current #each
thisCurrent iteration element
@index / @keyCurrent array index / object key in #each
@first / @lastBoolean -- first/last element in #each iteration

Subexpressions (nesting helpers)

Use () to nest one helper's output as input to another. The inner helper evaluates first:

{{uppercase (split record.fullName " " 0)}}              -- split then uppercase the first word
{{{base64Encode (join ":" record.user record.pass)}}}    -- join then encode
{{#compare (add record.qty 1) ">" "100"}}...{{/compare}} -- add then compare
{{#each (after record.tags 3)}}...{{/each}}              -- slice then iterate

Subexpressions can be nested multiple levels deep. Each () resolves inside-out.

Block helpers

  • {{#each record.items}}...{{/each}} -- iterate array or object
  • {{#if record.active}}...{{else}}...{{/if}} -- conditional
  • {{#compare val1 "==" val2}}...{{/compare}} -- comparison (==, ===, !=, !==, <, >, <=, >=)
  • {{#with record.address}}...{{/with}} -- change context scope

Date/time formatting

Uses moment.js tokens. Always use triple braces for date output.

Common tokens: YYYY (4-digit year), MM (2-digit month), DD (2-digit day), HH (24h hour), mm (minute), ss (second), SSS (millisecond), Z (timezone offset), X (Unix seconds), x (Unix milliseconds).

Timezone: pass as third argument -- {{{dateFormat "YYYY-MM-DD" record.date "US/Eastern"}}}.

Date arithmetic

dateAdd works in milliseconds:

  • 1 hour = 3,600,000
  • 1 day = 86,400,000
  • 7 days = 604,800,000

Runtime Context at Each Stage

What {{record.X}} or {{settings.Y}} actually resolves to depends on which bubble the expression runs in. The shapes below were captured by setting body: "{{{jsonSerialize this}}}" on import/lookup bubbles and echoing through a mirror endpoint — they represent exactly what's available at runtime.

Import bubble (HTTPImport, NetSuiteDistributedImport, etc.)

Body templates and Handlebars in mappings[].extract run per-record with this context:

{

Use this skill in a project

Open any RiverX project, search the Skills panel for celigo/ai/writing-handlebars, and install it in one click.

Use this skill