> ## 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.

# Composite topics

> Query across two or more topics in a single result — aligned on shared dimensions and views, without fan-out.

<Note>
  **Composite topics are currently in beta.** Also called multi-fact tables, they're available on request — reach out to your Omni contact or Omni support to opt into the beta.
</Note>

Composite topics let you query across **two or more independent topics** in a single result set, sharing dimensions across them and filtering each topic by its own attributes. Each topic is aggregated independently in its own subquery, and the results are stitched together with a `FULL OUTER JOIN` on the dimensions and views you mark as shared.

A composite topic keeps each fact in its own subquery, so every measure is computed against the correct grain. The result is a single analysis surface that pulls fields and filters from every topic.

## When to use a composite topic

Reach for a composite topic when **all** the following are true:

* You want measures from **two or more fact tables** in the same chart, table, or dashboard tile
* The fact tables share at least one **dimension** you'd join on (date, customer, region, product)

If you only need measures from a single fact table — even if it joins to several dimension tables — a regular [topic](/modeling/topics) is the right choice.

### Common patterns

| Pattern                     | Example                                                                         |
| --------------------------- | ------------------------------------------------------------------------------- |
| **Multi-fact dashboard**    | Compare orders revenue vs. marketing spend by month and region in one tile      |
| **Cross-domain KPI report** | A single table with weekly metrics from sales, support, and product domains     |
| **Constellation schema**    | Multiple fact tables that all join to the same date or customer dimension       |
| **Funnel across systems**   | Trials, conversions, and churn — each as their own topic, joined on cohort date |

### Composite topics vs. XLOOKUP

[`XLOOKUP`](/analyze-explore/calculations/position#xlookup) also lets you pull values from another query into the current one. For one-off, exploratory work, it's often the faster choice. Composite topics are the right tool when the cross-fact analysis needs to be reusable, governed, and available to other users.

| Use case                                                               | Reach for           |
| ---------------------------------------------------------------------- | ------------------- |
| Quick ad-hoc lookup between two query tabs in a workbook               | **XLOOKUP**         |
| One-off comparison you don't expect to repeat                          | **XLOOKUP**         |
| Cross-fact analysis you want to publish, share, or build dashboards on | **Composite topic** |
| Reusable definition where the join logic should live in the model      | **Composite topic** |

## How it works

```mermaid theme={null}
flowchart TD
    User["You select fields from a composite topic in a workbook"]
    Split["Omni splits the query into one subquery per topic"]
    A["Topic A<br/>aggregates its facts"]
    B["Topic B<br/>aggregates its facts"]
    C["Topic C<br/>aggregates its facts"]
    Join["FULL OUTER JOIN on shared dimensions<br/>(CROSS JOIN if no shared dims selected)"]
    Post["Shared measures, calcs, sorts, pivots,<br/>and limits applied to the post-join result"]

    User --> Split
    Split --> A
    Split --> B
    Split --> C
    A --> Join
    B --> Join
    C --> Join
    Join --> Post
```

**Each topic computes its measures independently, then results align on shared dimensions.** Nothing fans out.

## Field picker behavior

The workbook field picker organizes a composite topic's fields into a few groups:

| Group                 | Contents                                                                                                    |
| --------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Shared dimensions** | One entry per `shared_dimensions` definition. Selectable as a regular dimension.                            |
| **Shared measures**   | One entry per `shared_measures` definition. Selectable as a regular measure.                                |
| **Shared views**      | Dimensions from each shared view. Selectable. (Measures from shared views appear under each topic instead.) |
| **Per-topic**         | One group per included topic. Measures are selectable; dimensions are filter-only.                          |

## Known caveats and bugs

Current as of the latest beta release.

### Behaviors to be aware of

* **Topic-specific dimensions cannot be in `SELECT`.** They can only be used as filters; selecting one returns a query error. This is by design — there's no outer `GROUP BY` to make the result deterministic.
* **Shared dimensions can map differently-named columns, but the values must align.** Use `mappings:` to point each topic at its own field — the columns don't need to share a name or SQL definition. They do need to represent the same logical value: if the underlying SQL differs in a way that changes the result (different timezone conversions, different casing, etc.), rows won't align on the join even though the model validates.
* **Shared measures don't re-aggregate.** Each per-topic subquery aggregates first, then the shared measure runs over the joined result row-by-row. Wrapping a field in `SUM(...)` or setting `aggregate_type:` won't do what you expect — see [shared\_measures](/modeling/composite-topics/parameters/shared-measures) for details.
* **Filters on shared measures can't be pushed down.** They're applied as a `WHERE` on the post-join result. This is correct, but means a filter on a shared measure won't reduce the size of the per-topic subqueries.
* **Only topics with selected fields are included in the join by default.** To improve query performance, Omni only includes topics with selected fields in the `FULL OUTER JOIN`. If you need all topics included regardless of selection, set [`always_join_all_topics: true`](/modeling/composite-topics/parameters/always-join-all-topics). This optimization can significantly improve performance when you have several topics defined but only need measures from one or a subset of them.
* **Fields directives on included topics are enforced at query runtime.** If an included topic excludes fields via the [fields](/modeling/topics/parameters/fields) directive, those fields cannot be queried through the composite topic. Queries attempting to use excluded fields will return an error.

### Known bugs

* **Flattening a pivot on a shared dimension errors.** Building a pivot table on a composite topic where the pivot field is a shared dimension and clicking **Flatten** returns `No such topic <subtopic name>`. A fix is in progress.
* **Period-over-period can error on composite topics.** Adding a period-over-period comparison to a query with composite topic measures can return an error in some cases.

### Access controls and AI context

Access grants, row-level security, and AI context defined on each included topic continue to apply when that topic is queried as part of a composite. The composite topic itself does not currently support its own `required_access_grants`; control access by gating the included topics.

## We want your feedback

Composite topics are in **beta** — your input shapes GA. We're especially interested in:

* **Use cases that don't fit** — what cross-fact analyses are you trying to do that this doesn't support?
* **YAML ergonomics** — is the `shared_dimensions` / `shared_measures` / `shared_views` shape intuitive? Are there parameters you expected to find?
* **Workbook UX rough edges** — confusing menus, unclear errors, missing affordances
* **Performance** — slow plans, surprising query shapes, cases where the subquery breakdown produces expensive SQL

## Roadmap

### Modeling

* **Remove `@` from `shared_measures` syntax.**

### Workbook

* **Consolidate composite topics into the main topic picker.** Composite topics appear in their own group rather than mixing into existing topic subfolders alongside regular topics. We plan to surface them together so end users don't need to distinguish between the two.
* **Workbook-side editing for composite topics**, similar to the topic editor for regular topics.
* **Promote a calculation to a shared measure.** If you build a calc in a workbook that combines fields from multiple topics, you'll be able to promote it directly into the composite topic's `shared_measures` block — the same flow as promoting a calc to a regular measure today.
* **Column totals.** Support for column totals on composite topic results.
* **General workbook UI improvements.** We plan to invest some thought into cleaning up the design based on feedback, including tightening field indentation in the field browser.

### Agent support

* **Support interaction through Omni Agents**. Natural language workflows such as querying or modeling composite topics are not currently supported with composite topics.

If we make breaking changes, we'll publish a migration note and reach out to teams using the beta directly.

## Next steps

* [Create a composite topic](/modeling/composite-topics/create) — set one up in the model IDE and refine its shared views, dimensions, and measures.
* [Composite topic examples](/modeling/composite-topics/examples) — worked composite topics you can adapt.
* [Composite topic parameters](/modeling/composite-topics/parameters) — the full parameter reference.
* [Curating datasets with topics](/modeling/topics) — overview of regular topics and how they fit into the model.
