Documentation Index

Fetch the complete documentation index at: https://help.quickbase.com/llms.txt

Use this file to discover all available pages before exploring further.

Start with Jinja in Pipelines

Prev Next

What is Jinja and why do I need it?

A pipeline automates tasks by moving data between steps. When a trigger happens in one place an action happens in another. But, the data moving between steps rarely fits perfectly. You'll often need to combine two fields, format a date, branch on a condition, or build a list.

Jinja is a templating language that fills in placeholders with real data when the pipeline runs. Write it into any field that accepts text, wrapped in curly braces, and Pipelines evaluates it when the run happens.

Use Jinja any time you want to:

  • Combine values from earlier steps, ex. combining a first name and last name.

  • Change a value before sending it on, ex. formatting a numerical value as a date.

  • Make a decision, ex. writing VIP if the customer meets a set criteria, or leaving it blank if they don’t.

  • Handle a list, ex. having one line per record returned by a search step.

The moment a pipeline needs to use data from a previous step or react to what's coming in, you need something in place of static text. Jinja is that something. You don't have to learn all of Jinja to get value from it—most pipelines use a handful of common patterns.

Glossary

Term

What it means

Step

One action in a pipeline
Ex: Look up a record

Field

A piece of data on a record
Ex: Customer name

Trigger

The event that starts a pipeline

Ex: A record was created in a table

Search step

A step that returns a list of records matching a filter

Designer

The visual editor where you build a pipeline

Code mode

When you select the </> icon on a field to type a raw value yourself

Activity log

A history of every pipeline run, with every step's output—open via the pipeline's More menu (3-dot icon), then select View activity

What Jinja looks like

Here's a Jinja expression:

{{a.first_name}} {{a.last_name}}

In a pipeline step, this prints the first and last names from the previous step. The Reference steps section of this article explains what a means. The Common tasks table shows how to combine values, and Debug your pipeline covers what to do when things go wrong.

Jinja isn't the Quickbase formula language. The two share goals but use different syntax. IfThenElse(...) is a formula; {% if ... %}...{% endif %} is Jinja.

Common tasks

I want to…

Try this

Combine two fields

{{a.first_name}} {{a.last_name}}

Concatenate without spaces

{{a.first ~ a.last}}

Uppercase a value

{{a.name | upper}}

Round a number

{{a.amount | round(2)}}

Today's date

{{time.today}}

Date 7 days from now

{{time.today + time.delta(days=7)}}

If / else

{% if a.amount > 100 %}High{% else %}Low{% endif %}

Loop through a list

{% for r in b %}{{r.name}}{% endfor %}

Fall back if empty

{{a.note | default('No notes')}}

Clear a field

{{CLEAR}}

Detect a changed field

{% if a.status != a.$prev.status %}…{% endif %}

For more, see Common Jinja expressions.

Where to write Jinja

Most fields in a step accept Jinja. Select the code icon </> next to a field to switch it into code mode, then type your expression. Once you type {{, the field starts validating and formatting as you go.

To start, drag a field tile from the Variables panel into a code-mode field. The Designer writes the dot notation for you.

Note: A few fields don't accept Jinja and use a different language instead. The most common case is Advanced Query / filter fields on Quickbase search and trigger steps. Those use Quickbase query syntax, not Jinja. See Jinja reference for the syntax. If your Jinja stops working in a filter field, that's probably why.

Reference steps

Every step in a pipeline gets a letter: the first is a, the second is b, the third is c, and so on.

When you write b.customer_name, it means: the customer_name field from the second step.

For a Record Created trigger, step a is the record that fired the trigger, and a.field_name gets any field on it.

Three ways to reach a field

{{a.first_name}}                   # standard
{{a['Date Created']}}              # field name has spaces
{{a.get('phone', 'No phone')}}     # with a default if missing

Use brackets when the field name has spaces or matches a reserved word like items.

For address fields, use brackets when the parent label has spaces:

{{a['Mailing Address'].city}}

Single records vs. lists

Triggers and lookups return one record. a.field works directly.

Searches and Get All steps return a list, even if only one record matches. Don't dot-access them—use the first item, or loop:

{{b[0].customer_name}}             # first record

{% for r in b %}                   # all records
{{r.customer_name}}
{% endfor %}

If you see an error like TypeError: 'list' object has no attribute… in the activity log, you tried to dot-access a list when you should have looped or indexed.

In the Designer, list-returning steps show a green indicator on their output and single-record steps show blue.

Track what changed with $prev

When a record is updated, compare current and previous values with $prev:

{% if a.status != a.$prev.status %}
Status changed from {{a.$prev.status}} to {{a.status}}.
{% endif %}

Warning: $prev only works on Record Updated triggers—not on Create or Delete. It goes between the step letter and the field: a.$prev.field_name, not $prev.a.field_name. It also doesn't work inside Quickbase Advanced Query filter strings.

A common use is an audit-log pipeline that writes a row per field change.

Empty a field intentionally with {{CLEAR}}

By default, Pipelines refuses to write an empty value to a field. It silently skips it instead, to protect you from accidentally wiping data.

If you actually want to clear a field, use {{CLEAR}}:

{% if a.priority == 'No priority' %}{{CLEAR}}
{% else %}{{a.priority}}
{% endif %}

{{CLEAR}} only works in a step that writes data back—typically Create or Update.

Conditionals and loops

Use conditionals

A conditional asks a yes/no question and follows one path if true, another if false. Is the amount over $1,000? Label it "Big." Is it not? Check the next condition.

Example: Label every order as "Big," "Medium," or "Small" depending on the amount.

{% if a.amount > 1000 %}Big
{% elif a.amount > 100 %}Medium
{% else %}Small
{% endif %}

If the amount is bigger than 1,000, write "Big." Otherwise, if it's bigger than 100, write "Medium." Otherwise, write "Small."

The pattern is always:

  • {% if … %}—the question to check

  • {% elif … %}—(optional) another question if the first one was no

  • {% else %}—(optional) what to do if nothing matched

  • {% endif %}—closes the block

You can also use if on its own to write something only when a condition is true:

{% if a.is_vip %}
This customer is a VIP.
{% endif %}

Use loops

A loop is how you handle a list of things, like 1 line per customer, 1 entry per order, or 1 row per search result.

Example: A search step returned a list of customers, and you want to print every customer's name on its own line.

{% for customer in b %}
{{customer.name}}
{% endfor %}

For each customer in the list b, write that customer's name.

The pattern is always:

  • {% for X in Y %}—go through every item in the list Y. The name X is a placeholder; customer in this example, but r, item, or any valid variable name works.

  • The lines in the middle—what to do for each item, using the placeholder name (customer) to reach its fields

  • {% endfor %}—closes the block

While inside the loop, Jinja gives you a few useful helpers:

  • loop.index—position of the current item, counting from 1 (the third item has loop.index of 3)

  • loop.last—true on the last item only

  • loop.length—the total number of items

Use loop.last to add a comma after every item except the last:

{% for c in b %}{{c.name}}{% if not loop.last %}, {% endif %}{% endfor %}

That writes Alice, Bob, Carol instead of Alice, Bob, Carol,. For the full set of loop helpers, see the Jinja reference.

Why the curly-brace patterns are different

Both patterns use {% %}—curly braces with a percent sign. That's because they're instructions, not values.

  • {{ ... }}show me this value (double curly braces)

  • {% ... %}do something, like an if or a loop (curly braces with a percent)

The runtime object

Every pipeline run has a runtime object with information about itself:

Pipeline "{{runtime.pipeline_name}}" failed.
View activity: {{runtime.activity_url}}

Available properties: pipeline_name, pipeline_id, pipeline_url, run_id, activity_url, triggered_at, user_id.

On Quickbase triggers, you also get a context object with details about the table and user:

Updated in {{a.context.table_name}} ({{a.context.app_name}})
at {{a.context.occurred_at}} by {{a.context.user}}.

Debug your pipeline

Open the pipeline, then select the More menu (3-dot icon) > View activity. The activity log shows every step's rendered Jinja, color-coded by data type.

Symptom

Likely cause

Fix

Output renders as literal None

You combined a null value with text

Add | default('')

Output missing from the log

Empty value silently skipped

Use {{CLEAR}} if intentional, or default to fall back

Validation error: Incorrect template

Jinja syntax error

Check for missing {% endif %} or {% endfor %}, unmatched quotes, or stray whitespace in JSON

TypeError: 'NoneType' object has no attribute X

You reached for a field on a null value

Guard with {% if a.field is defined and a.field is not none %}

Use AI to draft expressions

Once you're comfortable with the basics, the Pipelines AI can write Jinja for you. Open code mode on any field and select the AI suggestion icon. Describe what you want in plain language (for example, set this to 7 days after the trigger date or build a list of customer emails separated by semicolons) and the AI proposes a Jinja expression you can review and edit before applying.

The expressions it generates make more sense, and are easier to review and adjust, once you're familiar with the patterns in this article.

Where to go next