> ## Documentation Index
> Fetch the complete documentation index at: https://docs.penbox.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Variables & scope

> Reference data from forms, cases, contacts, and system values

Every penscript expression runs within a **scope** — the collection of variables available at evaluation time. The scope contains form data, contact information, case data, and system values. Operators read from the scope to produce dynamic results.

## Referencing Variables

Variables are referenced using curly braces:

```json theme={null}
"{user.given_name}"
```

Dot notation accesses nested values:

```json theme={null}
"{data.address.city}"
"{contacts.main.email}"
```

When a variable is used inside a JSON string, it's resolved at evaluation time and replaced with its value. When used as the entire value of a JSON key, it resolves to its native type (number, array, object, etc.) rather than being converted to a string.

## System Variables

penscript provides built-in system variables available in every scope.

| Variable   | Description      |
| ---------- | ---------------- |
| `{$today}` | The current date |

System variables are prefixed with `$` to distinguish them from user-defined data.

## Inline Pipes

Variables support pipe expressions for inline transformations — lightweight operations applied directly inside a string reference, without needing a full JSON operator.

```json theme={null}
"{$today | formatDdMmYyyy}"
// → "27/01/2026"

"{my_var | formatDdMmYyyy}"
// Scope: { "my_var": "2015-10-20" }
// → "20/10/2015"

"{data.birthdate | age}"
// → 34
```

Pipes are evaluated left to right. The variable value is passed through the pipe function, and the result replaces the entire expression.

## Inline Comparisons & Ternaries

Simple logic can be expressed directly inside strings, without switching to JSON operators like `:if` or `:cmp`. This keeps lightweight conditions readable and compact.

**Boolean comparisons:**

```json theme={null}
"{ my_date > $today }"
// → true if my_date is after today

"{ my_date == $today }"
// → equality check with today

"{ data.birthdate | age >= 18 }"
// → true or false
```

**Combined conditions:**

```json theme={null}
"{ my_date != $today | my_date < $today }"
// → true if my_date is not today or is in the past
```

**Ternary expressions:**

```json theme={null}
"{ my_date > $today ? 'Future' : 'Past' }"
// → "Future" or "Past"
```

Inline expressions are ideal for short conditions in notifications, labels, and simple visibility rules. For complex branching with multiple outcomes, use the `:if` or `:case` JSON operators instead.

## Scope Resolution

When an expression references a variable, penscript resolves it by looking through the current scope. If a variable is not found, the reference resolves to `undefined` rather than throwing an error.

In nested contexts — like a `:map` loop inside a `:define` block — inner scopes can access variables from outer scopes. If a variable name exists in both the inner and outer scope, the inner scope takes precedence.

The full variable reference — all namespaces, every available key, and where each can be used — is documented in the Reference section.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="How penscript works" icon="gears" href="/penscript/how_it_works">
    Expression modes and operator composition
  </Card>

  <Card title="Logic & comparisons" icon="code-branch" href="/penscript/logic">
    Conditions, branching, and boolean logic
  </Card>

  <Card title="Numbers & calculations" icon="calculator" href="/penscript/numbers">
    Arithmetic and formatting
  </Card>

  <Card title="Reference" icon="book" href="/penscript/reference">
    Full variable reference
  </Card>
</CardGroup>
