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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.omni.co/feedback

```json
{
  "path": "/modeling/models/format-values",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Formatting values

> Format dimension and measure values with named formats, Excel-style strings, conditional formats, model constants, locale settings, and Markdown table cells.

Formatting controls how values display in queries and visualizations. You set a format on a [dimension](/modeling/dimensions/parameters/format) or [measure](/modeling/measures/parameters/format) using the `format` parameter, or define reusable formats at the model level with [`custom_formats`](/modeling/models/custom-formats).

Formats can also be set on a per-query basis from visualization configuration, using the same format types.

## Common questions

<AccordionGroup>
  <Accordion title="When are formats applied?">
    Formats are applied **after** the SQL runs, so they do not impact grouping. To handle grouping with truncation, use `ROUND()` or `FLOOR()`.
  </Accordion>

  <Accordion title="How are custom formats and model constants different?">
    While both `custom_formats` and `constants` enable reusability, they serve different purposes:

    * Use [`custom_formats`](/modeling/models/custom-formats) when you need to define a complete format object that will be used across multiple fields
    * Use [`constants`](/modeling/models/constants) when you need a reusable string value that might be used in format strings or other contexts
  </Accordion>

  <Accordion title="Can I use model constants in formats?" id="constants-in-formats">
    Yes. You can reuse a [model constant](/modeling/models/constants) inside any format string — named, custom Excel-style, or a conditional format branch — with `@{constant_name}`:

    ```yaml title="Model file" theme={null}
    constants:
      compact_time:
        value: 'm:ss "min"'
      margin_display:
        value: '#,##0.00 "bps"'
    ```

    ```yaml title="Dimension or measure" theme={null}
    dimensions:
      margin:
        sql: '"margin_bps"'
        format: "@{margin_display}"
    ```

    Constants are validated against the model: unknown names and malformed `@{...}` references surface as model validation issues in the IDE.
  </Accordion>

  <Accordion title="Do I need a constant to reuse a named format?" id="constant-to-reuse-format">
    No. If a [named format](#named-formats) like `usdcurrency_2` or `percent_1` already does what you need, use it directly — there is no benefit to wrapping a named format in a constant.
  </Accordion>

  <Accordion title="How do formats work with Markdown?" id="formats-with-markdown">
    There are two separate ways Markdown can factor in:

    | Approach                                                 | How                                                                                                                              | When to use                                                                                         |
    | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
    | `format` with a [Mustache template](#mustache-templates) | Add `{{field}}` references to a format string. Omni fills them in at display time and returns **plain text**.                    | You want to pull in values from other fields — for example, a currency symbol that changes per row. |
    | `markdown` parameter                                     | A separate Mustache template on a dimension or measure that Omni renders through its Markdown processor in **data table** cells. | You want Omni itself to render bold text, links, or images directly in the workbook table.          |

    The key difference: `format` returns **plain text**; `markdown` returns **rendered Markdown HTML** in table cells.

    You can set both on the same field: `format` controls display in standard value cells (and for numeric/date fields); `markdown` takes over when the column is shown as Markdown in a table visualization.

    See [Mustache templates](#mustache-templates), [Dimension `markdown`](/modeling/dimensions/parameters/markdown), and [Measure `markdown`](/modeling/measures/parameters/markdown) for syntax and examples.
  </Accordion>
</AccordionGroup>

## Where to define formats

Formats can be defined in two places:

| Approach        | Where                                                                                                                              | Use when                                                                                |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| **Field-level** | The `format` parameter on a [dimension](/modeling/dimensions/parameters/format) or [measure](/modeling/measures/parameters/format) | The format is specific to a single field                                                |
| **Model-level** | The [`custom_formats`](/modeling/models/custom-formats) parameter in a model file                                                  | The same format is used across multiple fields and you want to maintain it in one place |

Both approaches support the same format types — the difference is whether the format is defined inline on the field or defined once and referenced by name.

## Choosing a format type

Formats accept four shapes. Pick the one that matches your use case:

| Use this                                   | When you want to                                                                                                                                                                                                                                                | Examples                                              |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| [Named format](#named-formats)             | Apply a built-in format. Start here — named formats handle currency, percentages, and compact numbers. Use a currency prefix like `usd`, `gbp`, or `jpy` for a specific currency; omit the prefix to use the [locale's default](#locale-and-number-formatting). | `currency_2`, `usdaccounting_0`, `percent_1`, `big_2` |
| [Excel-style string](#excel-style-strings) | Control layout beyond what named formats offer — append units, add text, use semicolon sections for positive/negative display, or add [Mustache](#mustache-templates) `{{field}}` references to interpolate other row values.                                   | `'#,##0.00 "kg"'`, `'"{{currency.raw}}" #,###.00'`    |
| [Conditional format](#conditional-formats) | Choose the format at runtime based on a field value, user attribute, or filter. Each branch can reference a named format, an Excel-style string, or a [model constant](#constants-in-formats).                                                                  | `depends_on: { field: currency_code }`                |
| [Reusable format](#custom-formats)         | Define a reusable format at the model level. Reusable formats can include named formats, Excel-style strings, or conditional logic.                                                                                                                             | `format: dynamic_currency`, `format: margin_bps`      |

### Named formats

Numeric and currency formats default to two decimal places, with the exception of `id`. You can explicitly set decimal places by appending `_<number_of_places>` (up to 4) to a numeric or currency format. For example, `format: number_4`, `format: big_1`, `format: usdaccounting_0`.

When decimal length isn't set, decimals will be truncated to the shortest possible length for each row.

#### Numeric formats

| Format      | Example                       | Notes                                                                |
| ----------- | ----------------------------- | -------------------------------------------------------------------- |
| `number`    | 1,234.50 (`number_2`)         |                                                                      |
| `percent`   | 24.4% (`percent_1`)           |                                                                      |
| `id`        | 123450                        | Numbers, no commas                                                   |
| `billions`  | 1.20B (`billions_2`)          |                                                                      |
| `millions`  | 5.6M (`millions_1`)           |                                                                      |
| `thousands` | 8.90K (`thousands_2`)         |                                                                      |
| `big`       | 5.60M; 1.23K; 12.23 (`big_2`) | Uses `millions` if `>1M`; `thousands` if `>1000`; otherwise `number` |

#### Currency formats

Currency formats are available for **USD**, **EUR**, **GBP**, **AUD**, **JPY**, and **BRL**. Prefix the format category with the currency code (for example, `usdcurrency`, `jpyaccounting`). Formats without a currency prefix use the organization's default currency.

| Format category                                                              | Example                                     | Notes                            |
| ---------------------------------------------------------------------------- | ------------------------------------------- | -------------------------------- |
| `accounting` (e.g. `usdaccounting`, `jpyaccounting`)                         | \$(1,234.50) (`usdaccounting_2`)            |                                  |
| `currency` (e.g. `usdcurrency`, `gbpcurrency`)                               | -£1,234.50 (`gbpcurrency_2`)                |                                  |
| `bigcurrency` (e.g. `bigusdcurrency`, `bigjpycurrency`)                      | €5.60M; €1.23K; €12.23 (`biggbpcurrency_2`) | Compact display                  |
| `financial` (e.g. `audfinancial`, `brlfinancial`)                            | (1,234.50) (`financial_2`)                  | Does not contain a currency mark |
| `bigaccounting`, `bigfinancial` (e.g. `bigusdaccounting`, `bigjpyfinancial`) | Same compact rules as `big*` formats        |                                  |

#### Time formats

Time formats are available for [dimensions](/modeling/dimensions/parameters/format) only.

| Format                                                                | Notes                                                                      |
| --------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| [d3 time formats](https://github.com/d3/d3-time-format#locale_format) | Individual timeframe elements can be formatted using `timeframe_metadata`. |
| `"%Y-%m"`                                                             |                                                                            |
| `"%Y-%m-%d"`                                                          |                                                                            |
| `"%Y-%m-%d %H:%M:%S"`                                                 |                                                                            |

```yaml title="Time format with timeframe metadata" theme={null}
created_at:
  timeframe_metadata:
    month:
      format: "%Y-%m-%d"
```

### Excel-style strings

In addition to [named formats](#named-formats), formats accept Excel-style strings. These follow the same conventions as spreadsheet number formats.

<Tip>
  **For standard currency display**, prefer [named formats](#named-formats) like `usdcurrency_2` or `gbpaccounting_0`. Use Excel-style strings when you need layout control that named formats don't offer — for example, appending units, mixing text with numbers, or using semicolon sections for positive/negative display.
</Tip>

| Pattern         | Description                                  | Example output |
| --------------- | -------------------------------------------- | -------------- |
| `#,##0`         | Number with thousands separator, no decimals | 1,234          |
| `#,##0.00`      | Number with thousands separator, 2 decimals  | 1,234.56       |
| `0%`            | Percentage, no decimals                      | 75%            |
| `0.00%`         | Percentage, 2 decimals                       | 75.00%         |
| `0.00E+00`      | Scientific notation                          | 1.23E+03       |
| `#,##0 "units"` | Number with literal text suffix              | 1,234 units    |
| `#,##0.0,`      | Divide by 1,000 (trailing comma)             | 1.2            |
| `#,##0.0,,"M"`  | Divide by 1,000,000 with suffix              | 1.2M           |

#### Semicolon-separated sections

Excel-style format strings support up to four sections separated by semicolons, applied in order: **positive values**; **negative values**; **zero**; **text**. You can omit trailing sections — for example, two sections apply the first to positive values and the second to negative values.

```yaml theme={null}
format: '"🚀 "0.0;"📉 "-0.0;0'
```

This renders:

* Positive values as `🚀 1.5`
* Negative values as `📉 -1.5`
* Zero as `0`

Use quoted YAML strings so `"` and `;` parse correctly.

#### Mustache field references

Excel-style strings can include [Mustache](/visualize-present/mustache-reference) references to other field values using `{{view_name.field_name.property}}`. This lets you build format strings that incorporate values from other fields in the query, such as a dynamic currency symbol.

Supported properties:

| Property            | Description                     |
| ------------------- | ------------------------------- |
| `value`             | The formatted field value       |
| `raw`               | The unformatted field value     |
| `value_url_encoded` | The URL-encoded formatted value |

```yaml title="Dynamic currency symbol from another field" theme={null}
revenue:
  sql: '"amount"'
  aggregate_type: sum
  format: '#,##0.00 "{{orders.currency_symbol.value}}"'
```

<Warning>
  Referencing other fields in a format string implicitly requires those fields to be included in the query results. Omni will automatically add them, which may change the `GROUP BY` clause of the generated SQL.
</Warning>

<h3 id="mustache-templates">
  Mustache templates
</h3>

Any `format` string — named, Excel-style, or a conditional branch — can embed [Mustache](/visualize-present/mustache-reference) references to other fields in the row using `{{view_name.field_name.property}}` syntax. Omni resolves these references at display time before applying the format. What happens with the resolved string depends on the field type:

| Field type                                  | What Omni does with the resolved format string                                                                                                  |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **Number**                                  | Uses it as the Excel-style format string for the number. Use this to embed a dynamic symbol or suffix — for example, a per-row currency symbol. |
| **Date/time**                               | Uses it as the strftime format string, but only if it contains `%`. Resolved strings without `%` are silently ignored.                          |
| **All other types** (string, boolean, etc.) | Returns the resolved string directly as the field's display value. Use this to build a computed label from multiple fields.                     |

```yaml title="Dynamic currency symbol for a number (embed in format string)" theme={null}
measures:
  revenue:
    sql: '"amount"'
    aggregate_type: sum
    format: '"{{orders.currency_symbol.value}}" #,###.00'
```

```yaml title="Dynamic currency symbol as a conditional else branch" theme={null}
measures:
  total_value:
    format:
      depends_on:
        filter: reporting_currency_filter
        conditions:
          - condition:
              is: converted_EUR
            value: eurcurrency
          - condition:
              is: converted_USD
            value: usdcurrency
      else: '"{{order_items.reporting_currency_symbol.value}}" #,###.00'
```

```yaml title="Computed display value for a string field" theme={null}
dimensions:
  location:
    sql: '"city"'
    format: '{{orders.city.value}}, {{orders.country.value}}'
```

<Note>
  When used on a string or other non-number field, the resolved string is returned as **plain text** — it is not processed as Markdown HTML. If you need Markdown rendering in table cells (bold text, links, images), use the [`markdown`](/modeling/dimensions/parameters/markdown) parameter instead.
</Note>

Mustache templates in `format` can be made reusable using [`custom_formats`](/modeling/models/custom-formats) or [`constants`](#constants-in-formats), the same as any other format string.

### Conditional formats

Conditional formats apply different format strings depending on a runtime value — for example, formatting a `revenue` measure with the right currency symbol based on a `currency_code` dimension, or showing different decimal precision based on a user attribute.

Define a `depends_on` source and an ordered list of `conditions` using [Omni filter syntax](/modeling/filters):

| Source           | Resolves at            | Use when                                            |
| ---------------- | ---------------------- | --------------------------------------------------- |
| `field`          | Display time (per row) | The format depends on a value in the query results  |
| `user_attribute` | Query time             | The format depends on the user running the query    |
| `filter`         | Query time             | The format depends on a filter applied to the query |

The first matching condition determines the format. If no condition matches, the `else` format is used. See the [`custom_formats` documentation](/modeling/models/custom-formats#conditional-properties) for a complete list of properties.

```yaml title="Conditional format based on a field value" theme={null}
dimensions:
  currency_code:
    sql: '"currency_code"'
measures:
  revenue:
    sql: '"amount"'
    aggregate_type: sum
    format:
      depends_on:
        field: currency_code
        conditions:
          - condition:
              is: "USD"
            value: usdcurrency_0
          - condition:
              is: "GBP"
            value: gbpcurrency_0
        else: currency_0
```

```yaml title="Conditional format with numeric conditions" theme={null}
dimensions:
  age:
    sql: '"age"'
measures:
  total:
    sql: '"amount"'
    aggregate_type: sum
    format:
      depends_on:
        field: age
        conditions:
          - condition:
              greater_than: "18"
            value: "#,##0.00"
          - condition:
              between:
                - 10
                - 18
            value: "#,##0"
        else: "0"
```

```yaml title="Conditional format based on a user attribute" theme={null}
revenue:
  sql: '"amount"'
  aggregate_type: sum
  format:
    depends_on:
      user_attribute: preferred_currency
      conditions:
        - condition:
            is: "USD"
          value: usdcurrency_2
        - condition:
            is: "EUR"
          value: eurcurrency_2
      else: currency_2
```

```yaml title="Conditional format based on a filter value" theme={null}
revenue:
  sql: '"amount"'
  aggregate_type: sum
  format:
    depends_on:
      filter: currency_filter
      conditions:
        - condition:
            is: "USD"
          value: usdcurrency_2
        - condition:
            is: "GBP"
          value: gbpcurrency_2
      else: currency_2
```

```yaml title="Branch formats referencing model constants" theme={null}
constants:
  high_precision:
    value: "#,##0.0000"
  low_precision:
    value: "#,##0.0"

measures:
  measurement:
    sql: '"value"'
    aggregate_type: avg
    format:
      depends_on:
        field: unit_type
        conditions:
          - condition:
              is: "scientific"
            value: "@{high_precision}"
          - condition:
              is: "summary"
            value: "@{low_precision}"
      else: "@{low_precision}"
```

```yaml title="Reporting currency filter driving named formats" theme={null}
filters:
  reporting_currency:
    type: string
    suggestion_list:
      - value: converted_EUR
        label: Converted to EUR
      - value: converted_USD
        label: Converted to USD

measures:
  revenue_display:
    sql: '"amount"'
    aggregate_type: sum
    format:
      depends_on:
        filter: reporting_currency
        conditions:
          - condition:
              is: converted_EUR
            value: eurcurrency
          - condition:
              is: converted_USD
            value: usdcurrency
      else: usdcurrency
```

<h3 id="custom-formats">
  Reusable formats (`custom_formats`)
</h3>

Reusable formats are format objects defined in a model file using the [`custom_formats`](/modeling/models/custom-formats) parameter. They let you centrally manage format definitions and apply them consistently across multiple dimensions and measures.

Reusable formats can include any valid format type — named formats, Excel-style strings, Mustache templates, or conditional formats.

#### Referencing custom formats

Reference a reusable format using either a plain string or explicit object syntax:

**Plain string** (recommended):

```yaml theme={null}
<field_name>:
  format: <custom_format_name>
```

**Explicit object**:

```yaml theme={null}
<field_name>:
  format:
    custom_format: <custom_format_name>
```

See the [`custom_formats`](/modeling/models/custom-formats) parameter page for syntax, properties, and examples.

## Locale and number formatting

The [`default_numeric_locale`](/modeling/models/default-numeric-locale) model parameter controls how all formatted numbers are displayed — including the thousands delimiter, decimal delimiter, and default currency symbol. When you set a locale, every named format and Excel-style string in that model respects the locale's conventions automatically.

| Locale            | Thousands   | Decimal | Default currency | `currency_2` renders as |
| ----------------- | ----------- | ------- | ---------------- | ----------------------- |
| `en_US` (default) | `,`         | `.`     | `$`              | \$1,234.50              |
| `en_GB`           | `,`         | `.`     | `£`              | £1,234.50               |
| `fr_FR`           | ` ` (space) | `,`     | `€`              | €1 234,50               |
| `de_DE`           | `.`         | `,`     | `€`              | €1.234,50               |
| `ja_JP`           | `,`         | `.`     | `¥`              | ¥1,234.50               |
| `br_BR`           | `.`         | `,`     | `R$`             | R\$1.234,50             |
| `nl_NL`           | `.`         | `,`     | `€`              | €1.234,50               |

### Locale interaction with format types

* [**Named formats**](#named-formats) (`currency_2`, `accounting_0`, etc.) — The locale's default currency symbol is used when no currency prefix is specified. Prefixed formats like `usdcurrency_2` override the locale's default symbol.
* [**Excel-style strings**](#excel-style-strings) (`#,##0.00`) — the `#`, `,`, `.` tokens are locale-aware. A format of `#,##0.00` renders `1.234,50` under `de_DE`.
* [**Currency-prefixed named formats**](#named-formats) (`gbpcurrency_2`, `jpyaccounting_0`) — Always use the specified currency symbol, regardless of locale. The delimiter and decimal conventions still come from the locale.

## Durations and wallclock-style times

Timestamp dimensions should use strftime-style strings (they must include `%` in the format). See [Time formats](/modeling/models/format-values#time-formats).

For **numeric durations** stored as milliseconds (or seconds) that you want to display as hours, minutes, or seconds:

<Steps>
  <Step noAnchor>
    Convert the raw value to a fraction of a day (divide milliseconds by `86400000`). This will get the fraction that Excel-style time format codes expect.
  </Step>

  <Step noAnchor>
    Apply a format string using either:

    * An [**Excel-style string**](#excel-style-strings) (possibly through a [model constant](/modeling/models/constants)), or
    * A [**conditional format**](#conditional-formats) that picks a shorter or longer pattern based on how large the duration is (for example, show `h:mm:ss` when duration is at least 1 hour, otherwise `m:ss`).

    <Warning>
      `h` displays clock hours (wraps at 24). If your durations can exceed 24 hours, use `[h]` for elapsed hours — for example, `[h]:mm:ss` renders 25 hours as `25:00:00` instead of `1:00:00`. The same applies to `[m]` for elapsed minutes.
    </Warning>
  </Step>
</Steps>

```yaml title="Duration dimension: scale ms to Excel day fraction" theme={null}
dimensions:
  total_duration_ms:
    sql: '"total_duration_ms"'

  duration_as_excel_day:
    sql: ${total_duration_ms} / 86400000.0
    label: Total duration
    format:
      depends_on:
        field: total_duration_ms
        conditions:
          - condition:
              greater_than_or_equal_to: 3600000
            value: 'h "hr" mm "min" ss.0 "sec"'
          - condition:
              greater_than_or_equal_to: 60000
            value: 'm "min" ss.00 "sec"'
      else: 'ss.000 "sec"'
```

Adjust the thresholds (`3600000` ms = 1 hour, `60000` ms = 1 minute) to control when the display switches between hour-, minute-, and second-scale patterns.
