> ## Documentation Index
> Fetch the complete documentation index at: https://cubed3-cubesql-copy-command.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Dimensions

> Dimensions are attributes related to measures, such as country, age, or occupation. They support various types, formatting, and hierarchy membership.

You can use the `dimensions` parameter within [cubes][ref-ref-cubes] to define dimensions.
You can think about a dimension as an attribute related to a measure, e.g. the measure `user_count`
can have dimensions like `country`, `age`, `occupation`, etc.

Any dimension should have the following parameters: [`name`](#name), [`sql`](#sql), and [`type`](#type).

Dimensions can be also organized into [hierarchies][ref-ref-hierarchies].

## Parameters

### `name`

The `name` parameter serves as the identifier of a dimension. It must be unique
among all dimensions, measures, and segments within a cube and follow the
[naming conventions][ref-naming].

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products

      dimensions:
        - name: price
          sql: price
          type: number

        - name: brand_name
          sql: brand_name
          type: string


  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    dimensions: {
      price: {
        sql: `price`,
        type: `number`
      },

      brand_name: {
        sql: `brand_name`,
        type: `string`
      }
    }
  })
  ```
</CodeGroup>

### `case`

The `case` statement is used to define dimensions based on SQL conditions.

The `when` parameters declares a series of `sql` conditions and `labels`
that are returned if the condition is truthy. The `else` parameter declares
the default `label` that would be returned if there's no truthy `sql`
condition.

The following example will create a `size` dimension with values
`xl`, `xxl`, and `Unknown`:

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: size
          type: string
          case:
            when:
              - sql: "{CUBE}.size_value = 'xl-en'"
                label: xl
              - sql: "{CUBE}.size_value = 'xl'"
                label: xl
              - sql: "{CUBE}.size_value = 'xxl-en'"
                label: xxl
              - sql: "{CUBE}.size_value = 'xxl'"
                label: xxl
            else:
              label: Unknown
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      size: {
        type: `string`,
        case: {
          when: [
            { sql: `${CUBE}.size_value = 'xl-en'`, label: `xl` },
            { sql: `${CUBE}.size_value = 'xl'`, label: `xl` },
            { sql: `${CUBE}.size_value = 'xxl-en'`, label: `xxl` },
            { sql: `${CUBE}.size_value = 'xxl'`, label: `xxl` }
          ],
          else: { label: `Unknown` }
        }
      }
    }
  })

  ```
</CodeGroup>

The `label` property can be defined dynamically as an object with a `sql`
property in JavaScript models:

```javascript theme={"dark"}
cube(`products`, {
  // ...

  dimensions: {
    size: {
      type: `string`,
      case: {
        when: [
          {
            sql: `${CUBE}.meta_value = 'xl-en'`,
            label: { sql: `${CUBE}.english_size` }
          },
          {
            sql: `${CUBE}.meta_value = 'xl'`,
            label: { sql: `${CUBE}.euro_size` }
          },
          {
            sql: `${CUBE}.meta_value = 'xxl-en'`,
            label: { sql: `${CUBE}.english_size` }
          },
          {
            sql: `${CUBE}.meta_value = 'xxl'`,
            label: { sql: `${CUBE}.euro_size` }
          }
        ],
        else: { label: `Unknown` }
      }
    }
  }
})
```

### `title`

You can use the `title` parameter to change a dimension's displayed name. By
default, Cube will humanize your dimension key to create a display name. In
order to override default behavior, please use the `title` property:

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: meta_value
          title: Size
          sql: meta_value
          type: string
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      meta_value: {
        title: `Size`,
        sql: `meta_value`,
        type: `string`
      }
    }
  })
  ```
</CodeGroup>

### `description`

This parameter provides a human-readable description of a dimension.
When applicable, it will be displayed in [Playground][ref-playground] and exposed
to data consumers via [APIs and integrations][ref-apis].

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: comment
          description: Comments for orders
          sql: comments
          type: string
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      comment: {
        description: `Comments for orders`,
        sql: `comments`,
        type: `string`
      }
    }
  })
  ```
</CodeGroup>

### `public`

The `public` parameter is used to manage the visibility of a dimension. Valid
values for `public` are `true` and `false`. When set to `false`, this dimension
**cannot** be queried through the API. Defaults to `true`.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: comment
          sql: comment
          type: string
          public: false
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      comment: {
        sql: `comment`,
        type: `string`,
        public: false
      }
    }
  })
  ```
</CodeGroup>

### `format`

`format` is an optional parameter. It controls how dimension values are
displayed to data consumers. The available formats depend on the dimension type.

For `string` dimensions:

| Format     | Description                                                            |
| ---------- | ---------------------------------------------------------------------- |
| `imageUrl` | Display the value as an image, using the value itself as the image URL |
| `link`     | Display the value as a hyperlink, using the value itself as the URL    |

The `link` format also accepts an object form — `format: { type: link, label: … }` — so the
cell shows a label instead of the raw URL (see `crm_link` in the example below).

In [Workbooks][ref-workbooks], a `link`-formatted value renders as a clickable link in
table cells. Values that aren't `http`, `https`, or `mailto` URLs render as plain text.

In [Workbooks][ref-workbooks], an `imageUrl`-formatted value renders as an inline
thumbnail in table cells, with no chart configuration needed. Height, shape, and fit can
be adjusted per column on the chart's Style tab. Values that aren't `https` or
`data:image/*` URLs render as plain text.

<Info>
  Images at `https` URLs are fetched directly by the viewer's browser, so they must be
  publicly reachable — Cube does not proxy or cache them. `data:image/*` values are
  rendered inline and need no network access.
</Info>

A thumbnail is clickable only where the dimension also declares [`links`](#links). The
`imageUrl` format makes a value an image source, not a destination.

For `number` dimensions, you can use the same named formats and custom
[d3-format][link-d3-format] specifiers as [measures](/reference/data-modeling/measures#format):

| Format                        | Description              | Example        | Output     |
| ----------------------------- | ------------------------ | -------------- | ---------- |
| `number` / `number_N`         | Grouped fixed-point      | `number`       | 1,234.57   |
| `percent` / `percent_N`       | Percentage               | `percent_1`    | 12.5%      |
| `currency` / `currency_N`     | Currency with grouping   | `currency_0`   | \$1,235    |
| `abbr` / `abbr_N`             | SI prefix (K, M, G, …)   | `abbr`         | 1.2K       |
| `accounting` / `accounting_N` | Negatives in parentheses | `accounting_2` | (1,234.57) |
| `id`                          | Raw integer, no grouping | `id`           | 12345      |

For `time` dimensions, you can use [POSIX strftime][link-strftime] format strings
with [d3-time-format][link-d3-time-format] extensions (e.g., `%Y-%m-%d %H:%M:%S`).

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: total
          sql: amount
          type: number
          format: currency

        - name: image
          sql: "CONCAT('https://img.example.com/id/', {id})"
          type: string
          format: imageUrl

        - name: order_link
          sql: "'http://mywebsite.com/orders/' || id"
          type: string
          format: link

        - name: crm_link
          sql: "'https://na1.salesforce.com/' || id"
          type: string
          format:
            type: link
            label: View in Salesforce

        - name: created_at
          sql: created_at
          type: time
          format: "%Y-%m-%d %H:%M:%S"
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      total: {
        sql: `amount`,
        type: `number`,
        format: `currency`
      },

      image: {
        sql: `CONCAT('https://img.example.com/id/', ${id})`,
        type: `string`,
        format: `imageUrl`
      },

      order_link: {
        sql: `'http://mywebsite.com/orders/' || id`,
        type: `string`,
        format: `link`
      },

      crm_link: {
        sql: `'https://na1.salesforce.com/' || id`,
        type: `string`,
        format: {
          type: `link`,
          label: `View in Salesforce`
        }
      },

      created_at: {
        sql: `created_at`,
        type: `time`,
        format: `%Y-%m-%d %H:%M:%S`
      }
    }
  })
  ```
</CodeGroup>

Common time format examples:

| Format string       | Example output        |
| ------------------- | --------------------- |
| `%m/%d/%Y %H:%M`    | 12/04/2025 14:30      |
| `%Y-%m-%d %H:%M:%S` | 2025-12-04 14:30:00   |
| `%B %d, %Y`         | December 04, 2025     |
| `%b %d, %Y`         | Dec 04, 2025          |
| `%I:%M %p`          | 02:30 PM              |
| `%A, %B %d`         | Thursday, December 04 |
| `Q%q %Y`            | Q4 2025               |
| `Week %V, %Y`       | Week 49, 2025         |

### `currency`

The optional `currency` parameter specifies the [ISO 4217][link-iso-4217]
currency code for a `number`-type dimension. Use it alongside
`format: currency` to indicate which currency the values represent.

The value is a 3-letter currency code (e.g., `USD`, `EUR`, `GBP`) and is
case-insensitive.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: price
          sql: price
          type: number
          format: currency
          currency: EUR
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      price: {
        sql: `price`,
        type: `number`,
        format: `currency`,
        currency: `EUR`
      }
    }
  })
  ```
</CodeGroup>

<Info>
  The `currency` parameter can only be used with dimensions of type `number`.
  Using it with other dimension types will result in a validation error.
</Info>

### `links`

The `links` parameter allows you to define **one or more** links associated with a
dimension (it is a list). In [Workbooks][ref-workbooks], every link is available from the
table **cell context menu**, and the link marked `primary` also renders inline, as a
clickable link on the cell value itself.

Links are useful to let users navigate to related external resources (e.g., Google
search), internal tools (e.g., Salesforce), or other pages in a BI tool.

Each link must have a `name` and a `label`. The `name` is used as an identifier
in the [synthetic dimension](#synthetic) name.

A link must specify either a `url` or a `dashboard`:

* `url` is a SQL expression that constructs the link URL. It can [reference][ref-references]
  column and dimension values, just like the [`sql` parameter](#sql) or [`mask` parameter](#mask).
* `dashboard` is a target dashboard reference. When set, the link URL is generated as
  `/dashboard/<dashboard>` and `params` are appended as a query string. In Cube Cloud
  this is the target dashboard's **slug** (set in the dashboard's options and resolved
  within the current deployment); choosing the link drills in-app to that dashboard with
  `params` applied as equality filters. Links surface in the table **cell context menu**.

Optionally, a link might use the `icon` parameter to reference an icon from a [supported
icon set][link-tabler] to be displayed alongside the link label. Use the icon's kebab-case
name without any prefix (e.g. `brand-google`, `external-link`, `layout-dashboard`, `send`);
browse the available names at [tabler.io/icons][link-tabler]. When omitted, a default link
icon is shown.

Optionally, one link per dimension might set `primary: true`. In [Workbooks][ref-workbooks]
that link renders inline on the cell value, so it is reachable in one click while the rest
stay in the cell context menu. A dimension may mark at most one link as primary. Rows whose
primary link URL resolves to an empty value render the cell as plain text.

Optionally, a link might use the `target` parameter to specify [where to open it][link-target]:
`blank` to open in a new tab/window or `self` to open in the same tab/window. The default
depends on the link kind: `url:` links default to `blank` (new tab), while `dashboard:`
drill-ins default to `self` (in-app). An explicit `target` on a `dashboard:` drill-in is
honored on Cube **v1.7.5** or newer.

```yaml theme={"dark"}
cubes:
  - name: users

    dimensions:
      # Definitions of dimensions such as `email`, etc.

      - name: full_name
        sql: full_name
        type: string
        links:
          - name: google_search
            label: Search on Google
            url: "CONCAT('https://www.google.com/search?q=', {CUBE}.full_name)"
            icon: brand-google
            target: blank
            primary: true
          
          - name: salesforce_search
            label: Search in Salesforce
            url: "CONCAT('https://your-company.salesforce.com/search/results/?q=', {email})"
            target: blank

          - name: send_email
            label: Write an email
            url: "CONCAT('mailto:', {email})"
            icon: send
```

#### `params`

The optional `params` parameter can be used to add additional query parameters to the
URL. It accepts a map of key-value pairs, where keys are parameter names and values are
SQL expressions (just like `url`).

Values in `params` can [reference][ref-references] columns and dimension values.
All parameter values will be [URL-encoded][link-encode-uri-component] in the generated SQL
using a database-specific encoding function.

```yaml theme={"dark"}
cubes:
  - name: users

    dimensions:
      # Definitions of dimensions such as `id`, `country`, etc.

      - name: full_name
        sql: full_name
        type: string
        links:
          - name: performance
            label: Check performance dashboard
            dashboard: KSqDYdUz6Ble
            params:
              - key: filter_user_id
                value: "{id}"
              - key: filter_country
                value: "{country}"
```

#### Synthetic dimensions

Each link will be rendered as an additional [synthetic](#synthetic) dimension in the
result set, with the following naming convention:

* `<dimension_name>___link_<link_name>_url`

<Info>
  All references in link URLs and parameters must resolve to a single value for a given
  value of the dimension on which the link is defined. Otherwise, it will result in
  duplicate rows in the result set.
</Info>

### `meta`

The `meta` parameter allows you to attach arbitrary information to a dimension.
It can be consumed and interpreted by supporting tools.

You can also use the `ai_context` key to provide context to the
[AI agent][ref-ai-context] without exposing it in the user interface.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: users_count
          sql: "{users.count}"
          type: number
          meta:
            any: value
            ai_context: >
              This is a subquery dimension. Use it to get the
              number of users associated with each product.
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      users_count: {
        sql: `${users.count}`,
        type: `number`,
        meta: {
          any: "value",
          ai_context: `This is a subquery dimension. Use it to get the
            number of users associated with each product.`
        }
      }
    }
  })
  ```
</CodeGroup>

### `order`

The `order` parameter specifies the default sort order for a dimension. Valid
values are `asc` (ascending) and `desc` (descending). This parameter is optional.

When set, the dimension's default sort order is exposed via
[APIs and integrations][ref-apis]. Consuming applications, such as BI tools
and custom frontends, can use this metadata to apply consistent default sorting
when displaying dimension values, ensuring a uniform user experience across
different tools connected to the semantic layer.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: status
          sql: status
          type: string
          order: asc

        - name: created_at
          sql: created_at
          type: time
          order: desc
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      status: {
        sql: `status`,
        type: `string`,
        order: `asc`
      },

      created_at: {
        sql: `created_at`,
        type: `time`,
        order: `desc`
      }
    }
  })
  ```
</CodeGroup>

### `primary_key`

Specify if a dimension is a primary key for a cube. The default value is
`false`.

A primary key is used to make [joins][ref-schema-ref-joins] work properly.

<Info>
  Setting `primary_key` to `true` will change the default value of the [`public`
  parameter](#public) to `false`. If you still want `public` to be `true`, set it
  explicitly.
</Info>

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: id
          sql: id
          type: number
          primary_key: true
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      id: {
        sql: `id`,
        type: `number`,
        primary_key: true
      }
    }
  })
  ```
</CodeGroup>

It is possible to have more than one primary key dimension in a cube if you'd
like them all to be parts of a composite key:

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      sql: |
        SELECT 1 AS column_a, 1 AS column_b UNION ALL
        SELECT 2 AS column_a, 1 AS column_b UNION ALL
        SELECT 1 AS column_a, 2 AS column_b UNION ALL
        SELECT 2 AS column_a, 2 AS column_b

      dimensions:
        - name: composite_key_a
          sql: column_a
          type: number
          primary_key: true

        - name: composite_key_b
          sql: column_b
          type: number
          primary_key: true

      measures:
        - name: count
          type: count
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    sql: `
      SELECT 1 AS column_a, 1 AS column_b UNION ALL
      SELECT 2 AS column_a, 1 AS column_b UNION ALL
      SELECT 1 AS column_a, 2 AS column_b UNION ALL
      SELECT 2 AS column_a, 2 AS column_b
    `,

    dimensions: {
      composite_key_a: {
        sql: `column_a`,
        type: `number`,
        primary_key: true
      },

      composite_key_b: {
        sql: `column_b`,
        type: `number`,
        primary_key: true
      }
    },

    measures: {
      count: {
        type: `count`
      }
    }
  })
  ```
</CodeGroup>

Querying the `count` measure of the cube shown above will generate the following
SQL to the upstream data source:

```sql theme={"dark"}
SELECT
  count(
    CAST("product".column_a as TEXT) || CAST("product".column_b as TEXT)
  ) "product__count"
FROM (
  SELECT 1 AS column_a, 1 AS column_b UNION ALL
  SELECT 2 AS column_a, 1 AS column_b UNION ALL
  SELECT 1 AS column_a, 2 AS column_b UNION ALL
  SELECT 2 AS column_a, 2 AS column_b
) AS "product"
```

### `propagate_filters_to_sub_query`

When this statement is set to `true`, the filters applied to the query will be
passed to the [subquery][self-subquery].

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: users_count
          sql: "{users.count}"
          type: number
          sub_query: true
          propagate_filters_to_sub_query: true
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      users_count: {
        sql: `${users.count}`,
        type: `number`,
        sub_query: true,
        propagate_filters_to_sub_query: true
      }
    }
  })
  ```
</CodeGroup>

### `sql`

`sql` is a required parameter. It can take any valid SQL expression depending on
the `type` of the dimension. Please refer to the \[Dimension
Types]\[ref-schema-ref-dims-types] to understand what the `sql` parameter should
be for a given dimension type.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: created_at
          sql: created_at
          type: time
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      created_at: {
        sql: `created_at`,
        type: `time`
      }
    }
  })
  ```
</CodeGroup>

### `mask`

The optional `mask` parameter defines the replacement value used when the
dimension is masked by a [data masking][ref-data-masking] access policy.

The mask can be a static value (number, boolean, or string) or a SQL expression:

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: secret_code
          sql: secret_code
          type: string
          mask:
            sql: "CONCAT('***', RIGHT({CUBE}.secret_code, 3))"

        - name: revenue
          sql: revenue
          type: number
          mask: -1
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      secret_code: {
        sql: `secret_code`,
        type: `string`,
        mask: {
          sql: `CONCAT('***', RIGHT(${CUBE}.secret_code, 3))`
        }
      },

      revenue: {
        sql: `revenue`,
        type: `number`,
        mask: -1
      }
    }
  })
  ```
</CodeGroup>

If no `mask` is defined, the default mask value is `NULL`. See
[data masking][ref-data-masking] for more details.

### `sub_query`

The `sub_query` statement allows you to reference a measure in a dimension. It's
an advanced concept and you can learn more about it [here][ref-subquery].

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: products
      # ...

      dimensions:
        - name: users_count
          sql: "{users.count}"
          type: number
          sub_query: true
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`products`, {
    // ...

    dimensions: {
      users_count: {
        sql: `${users.count}`,
        type: `number`,
        sub_query: true
      }
    }
  })
  ```
</CodeGroup>

### `type`

`type` is a required parameter. There are various types that can be assigned to
a dimension. A dimension can only have one type.

| Type      | Description                                                                                                                                                                                                                                                                                      |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `time`    | Timestamp column for time series data. The target column should be `TIMESTAMP`; cast other temporal types in `sql`. See [this recipe][ref-string-time-dims] for string-based datetimes.                                                                                                          |
| `string`  | Text fields containing letters or special characters.                                                                                                                                                                                                                                            |
| `number`  | Numeric or integer fields.                                                                                                                                                                                                                                                                       |
| `boolean` | Boolean fields or data coercible to boolean.                                                                                                                                                                                                                                                     |
| `switch`  | Predefined set of allowed values (enum-like). Takes only a `values` sub-parameter — no `sql`, and no other parameters such as `title` or `public`. Useful for [`case` measures][ref-case-measures]. [Pre-aggregations][ref-matching-switch-dimensions] don't need to include it. Tesseract only. |
| `geo`     | Geographic coordinates. Requires `latitude` and `longitude` sub-parameters instead of `sql`.                                                                                                                                                                                                     |

<Warning>
  `switch` dimensions are powered by Tesseract, the [next-generation data modeling
  engine][link-tesseract]. In versions before v1.7.0, it was not enabled by default.
</Warning>

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      # ...

      dimensions:
        - name: completed_at
          sql: completed_at
          type: time

        - name: full_name
          sql: "CONCAT({first_name}, ' ', {last_name})"
          type: string

        - name: amount
          sql: amount
          type: number

        - name: is_enabled
          sql: is_enabled
          type: boolean

        - name: growth_window
          type: switch
          values:
            - 3m
            - 6m
            - 12m

        - name: location
          type: geo
          latitude:
            sql: "{CUBE}.latitude"
          longitude:
            sql: "{CUBE}.longitude"
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    // ...

    dimensions: {
      completed_at: {
        sql: `completed_at`,
        type: `time`
      },

      full_name: {
        sql: `CONCAT(${first_name}, ' ', ${last_name})`,
        type: `string`
      },

      amount: {
        sql: `amount`,
        type: `number`
      },

      is_enabled: {
        sql: `is_enabled`,
        type: `boolean`
      },

      growth_window: {
        type: `switch`,
        values: [`3m`, `6m`, `12m`]
      },

      location: {
        type: `geo`,
        latitude: {
          sql: `${CUBE}.latitude`
        },
        longitude: {
          sql: `${CUBE}.longitude`
        }
      }
    }
  })
  ```
</CodeGroup>

### `synthetic`

The `synthetic` parameter can't be set by a user directly. It is used to mark dimensions
that are automatically created by Cube, e.g., for [links](#links).

You can check if a dimension is synthetic via the [`/v1/meta` API endpoint][ref-meta-api].

### `granularities`

By default, the following granularities are available for time dimensions:
`year`, `quarter`, `month`, `week` (starting on Monday), `day`, `hour`, `minute`,
`second`.

You can use the `granularities` parameter with any dimension of the [type
`time`][ref-time-dimensions] to define one or more custom granularities, such as
a *week starting on Sunday* or a *fiscal year*.

<Note>
  See [this recipe][ref-custom-granularity-recipe] for more custom granularity
  examples.
</Note>

<Warning>
  Custom granularities are supported for the following [data sources][ref-data-sources]:
  Amazon Athena, Amazon Redshift, DuckDB, Databricks, Google BigQuery, ClickHouse, Microsoft SQL Server, MySQL, Postgres, and Snowflake.
  Please [file an issue](https://github.com/cube-js/cube/issues) if you need support for another data source.
</Warning>

<Warning>
  Custom granularities can be queried by name via the [REST API][ref-rest-api].
  However, neither the [SQL API][ref-sql-api] nor the [GraphQL
  API][ref-graphql-api] can address them by name: the SQL API only supports the
  default granularities in `DATE_TRUNC`, and the GraphQL schema only exposes
  fields for the default granularities. To query a custom granularity via the SQL
  API, the GraphQL API, or a BI tool, use a [proxy
  dimension][ref-proxy-granularity] that references it.
</Warning>

For each custom granularity, the `interval` parameter is required. It specifies
the duration of the time interval and has the following format:
`quantity unit [quantity unit...]`, e.g., `5 days` or `1 year 6 months`.

Optionally, a custom granularity might use the `offset` parameter to specify how
the time interval is shifted forward or backward in time. It has the same
format as `interval`, however, you can also provide negative quantities, e.g.,
`-1 day` or `1 month -10 days`.

Alternatively, instead of `offset`, you can provide the `origin` parameter.
When `origin` is provided, time intervals will be shifted in a way that one of
them will match the provided origin. It accepts an ISO 8601-compliant [date time
string][link-date-time-string], e.g., `2024-01-02` or `2024-01-02T12:00:00.000Z`.

Optionally, a custom granularity might have the `title` parameter with a
human-friendly description.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: orders
      sql: |
        SELECT '2025-01-01T00:12:00.000Z'::TIMESTAMP AS time UNION ALL
        SELECT '2025-02-01T00:15:00.000Z'::TIMESTAMP AS time UNION ALL
        SELECT '2025-03-01T00:18:00.000Z'::TIMESTAMP AS time

      dimensions:
        - name: time
          sql: time
          type: time

          granularities:
            - name: quarter_hour
              interval: 15 minutes

            - name: week_starting_on_sunday
              interval: 1 week
              offset: -1 day

            - name: fiscal_year_starting_on_april_01
              title: Corporate and government fiscal year in the United Kingdom
              interval: 1 year
              origin: "2025-04-01"
              # You have to use quotes here to make `origin` a valid YAML string 
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`orders`, {
    sql: `
      SELECT '2025-01-01T00:12:00.000Z'::TIMESTAMP AS time UNION ALL
      SELECT '2025-02-01T00:15:00.000Z'::TIMESTAMP AS time UNION ALL
      SELECT '2025-03-01T00:18:00.000Z'::TIMESTAMP AS time
    `,

    dimensions: {
      time: {
        sql: `time`,
        type: `time`,
        granularities: {
          quarter_hour: {
            interval: `15 minutes`
          },
          week_starting_on_sunday: {
            interval: `1 week`,
            offset: `-1 day`
          },
          fiscal_year_starting_on_april_01: {
            title: `Corporate and government fiscal year in the United Kingdom`,
            interval: `1 year`,
            origin: `2025-04-01`
          }
        }
      }
    }
  })
  ```
</CodeGroup>

### `time_shift`

The `time_shift` parameter allows overriding the time shift behavior for time dimensions
within [calendar cubes][ref-calendar-cubes]. Such time shifts can be referenced in
[time-shift measures][ref-time-shift] of other cubes, enabling the use of custom calendars.

The `time_shift` parameter can only be set on *time dimensions* within *calendar cubes*,
i.e., cubes where the [`calendar` parameter][ref-cube-calendar] is set to `true`.

The `time_shift` parameter accepts an array of time shift definitions. Each definition
can include `time_dimension`, `type`, `interval`, and `name` parameters, similarly to the
[`time_shift` parameter][ref-measure-time-shift] of time-shift measures. Additionally,
you can use the `sql` parameter to define a custom time mapping using a SQL expression.

<CodeGroup>
  ```yaml title="YAML" theme={"dark"}
  cubes:
    - name: fiscal_calendar
      calendar: true
      sql: >
        SELECT
          date_key,
          calendar_date,
          fiscal_date_prior_year,
          fiscal_date_next_quarter
        FROM calendar_table

      dimensions:
        - name: date_key
          sql: date_key
          type: time
          primary_key: true

        - name: date
          sql: calendar_date
          type: time
          time_shift:
            - name: prior_calendar_year
              type: prior
              interval: 1 year

            - name: next_calendar_quarter
              type: next
              interval: 1 quarter

            - name: prior_fiscal_year
              sql: "{CUBE}.fiscal_date_prior_year"

            - name: next_fiscal_quarter
              sql: "{CUBE}.fiscal_date_next_quarter"
  ```

  ```javascript title="JavaScript" theme={"dark"}
  cube(`fiscal_calendar`, {
    calendar: true,
    sql: `
      SELECT
        date_key,
        calendar_date,
        fiscal_date_prior_year,
        fiscal_date_next_quarter
      FROM calendar_table
    `,

    dimensions: {
      date_key: {
        sql: `date_key`,
        type: `time`,
        primary_key: true
      },

      date: {
        sql: `calendar_date`,
        type: `time`,
        time_shift: [
          {
            name: `prior_calendar_year`,
            type: `prior`,
            interval: `1 year`
          },
          {
            name: `next_calendar_quarter`,
            type: `next`,
            interval: `1 quarter`
          },
          {
            name: `prior_fiscal_year`,
            sql: `${CUBE}.fiscal_date_prior_year`
          },
          {
            name: `next_fiscal_quarter`,
            sql: `${CUBE}.fiscal_date_next_quarter`
          }
        ]
      }
    }
  });
  ```
</CodeGroup>

[ref-ai-context]: /docs/data-modeling/ai-context

[ref-ref-cubes]: /reference/data-modeling/cube

[ref-schema-ref-joins]: /reference/data-modeling/joins

[ref-subquery]: /docs/data-modeling/dimensions#subquery-dimensions

[self-subquery]: #sub-query

[ref-naming]: /docs/data-modeling/concepts/syntax#naming

[ref-playground]: /docs/explore-analyze/playground

[ref-apis]: /reference

[ref-time-dimensions]: #type

[link-date-time-string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format

[ref-custom-granularity-recipe]: /recipes/data-modeling/custom-granularity

[ref-rest-api]: /reference/core-data-apis/rest-api

[ref-graphql-api]: /reference/core-data-apis/graphql-api

[ref-sql-api]: /reference/core-data-apis/sql-api

[ref-proxy-granularity]: /docs/data-modeling/dimensions#time-dimension-granularity-references

[ref-ref-hierarchies]: /reference/data-modeling/hierarchies

[ref-data-sources]: /admin/connect-to-data/data-sources

[ref-calendar-cubes]: /docs/data-modeling/concepts/calendar-cubes

[ref-time-shift]: /docs/data-modeling/measures#time-shift

[ref-cube-calendar]: /reference/data-modeling/cube#calendar

[ref-measure-time-shift]: /reference/data-modeling/measures#time_shift

[ref-data-masking]: /docs/data-modeling/data-access-policies#data-masking

[link-iso-4217]: https://en.wikipedia.org/wiki/ISO_4217

[link-d3-format]: https://d3js.org/d3-format

[link-strftime]: https://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html

[link-d3-time-format]: https://d3js.org/d3-time-format

[link-tesseract]: https://cube.dev/blog/introducing-next-generation-data-modeling-engine

[ref-case-measures]: /reference/data-modeling/measures#case

[ref-matching-switch-dimensions]: /docs/pre-aggregations/matching-pre-aggregations#matching-switch-dimensions

[ref-meta-api]: /reference/core-data-apis/rest-api/reference#base_path/v1/meta

[ref-string-time-dims]: /recipes/data-modeling/string-time-dimensions

[ref-workbooks]: /docs/explore-analyze/workbooks

[link-target]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a#target

[link-tabler]: https://tabler.io/icons

[ref-references]: /docs/data-modeling/concepts/syntax#references

[ref-filter-params]: /reference/data-modeling/context-variables#filter_params

[link-encode-uri-component]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

[ref-rest-filters]: /reference/core-data-apis/rest-api/query-format#query-properties
