> ## 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/develop/shared-extensions/index",
  "feedback": "Description of the issue"
}
```

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

</AgentInstructions>

# Shared extension models

> Create an inheritance model for multi-tenant environments with shared extension models.

Shared extension models let you create specialized versions of a parent model that inherit its core logic — joins, topics, metrics — while allowing their own customizations. For example, you could create:

* **Multi-tenant environments** - Dynamically route users to tenant-specific extensions based on [user attribute mapping](/administration/users/attributes), giving each customer a tailored data experience from a single parent model.
* **Departmental models** - Use an extension as the static base model for a workbook, giving teams like Finance or Marketing their own curated view of shared data without affecting other groups.

<iframe width="640" height="416" src="https://www.loom.com/embed/cffa58055ba547169f09eb90779961d2" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen />

## When to use shared extensions

Shared extensions may be a good fit when:

* You manage a multi-tenant environment and need to give each customer a tailored data experience
* You have a core set of metrics and joins that should be consistent across all customers
* You want customers to build their own content without affecting other tenants
* You need to programmatically provision and route users to siloed data views at scale

Shared extensions **are not recommended** for:

* Environments where every customer requires a completely different schema or data source with no common logic
* Situations where changes made by one customer should flow back up and be visible to everyone else

## Requirements

To follow the steps in this guide, you'll need:

* **To have shared extension models enabled.** Contact Omni support to have this feature enabled.
* **Organization Admin** or **Connection Admin** permissions for the connection you want to work with in Omni.

## Creating shared extensions

<Steps>
  <Step title="Create the extension model" titleSize="h3">
    1. Navigate to the **Develop** menu and select your parent connection.
    2. Open the model and click **Model > New Shared Extension**.
    3. Enter a name for the extension (e.g., `customer_3`).
    4. **Optional**: Select the **Allow exploration** checkbox. Enable this option if you want users to build their own content off the extension rather than viewing existing dashboards. See [Extension settings](/modeling/develop/shared-extensions/settings#allow-exploration) for more on how this setting behaves.
  </Step>

  <Step title="Define model visibility with user attributes" titleSize="h3">
    Next, you'll use [user attributes](/administration/users/attributes) to control which model extension a user sees when accessing or building content.

    1. Navigate to **Settings > Attributes**.
    2. Click **New Attribute**.
    3. Define a name and a reference (e.g., `customer_attribute`).
    4. Assign the appropriate attribute value to your [users](/administration/users).
  </Step>

  <Step title="Map user attributes in the model" titleSize="h3">
    To route users to the correct extension, you'll add a mapping to the parent model using the `dynamic_shared_extensions` parameter.

    1. Click **Develop** in the left navigation.

    2. Navigate to the parent model.

    3. In the model file, create the attribute mappings:

           <Tabs>
             <Tab title="Manual mapping">
               In this approach, you use the `mappings` parameter to create individual mappings to user attributes:

               ```yaml title="Manual mapping" theme={null}
               dynamic_shared_extensions:
                 user_attribute: customer_attribute # User attribute reference
                 mappings:
                   customer_3:                      # User attribute value
                     model: customer_3              # Extension model name
                   customer_2:
                     model: customer_2
               ```
             </Tab>

             <Tab title="Programmatic mapping">
               If your user attributes follow a consistent naming convention, you can use the `map_pattern` parameter to create programmatic mappings:

               ```yaml title="Programmatic mapping" theme={null}
               dynamic_shared_extensions:
                 - map_pattern: merchant_{{omni_attributes.merchant_id}}
               ```
             </Tab>
           </Tabs>

           <Note>
             Only one of the `mappings` or `map_pattern` parameters can be used at a time.
           </Note>

    4. Save the changes.
  </Step>

  <Step title="Define default access for users" titleSize="h3">
    Setting default access levels ensures users only see the data intended for them.

    To start, set your parent connection base access to **No Access**. This prevents users from building off any extensions until you explicitly grant permission.

    1. Click **Settings > Connections**.
    2. In the list of connections, click the **parent connection** of the extension model.
    3. Click the **Permissions** tab.
    4. Set the connection's **Base Access** to **No Access**.
    5. Click **Save changes**.
    6. Choose how to approach permissions:

           <AccordionGroup>
             <Accordion title="Option 1: Shared content access (preferred)" description="Creates an experience that allows shared content">
               Even with **No Access** applied to the specific child extension, Omni will automatically route the user to the proper model when they view or build content. This allows them to see shared dashboards while being restricted to their own data scope.

               **To implement this approach**, grant users access to the **parent** model - for example, as Restricted Queriers - but set all child extensions to **No Access**.
             </Accordion>

             <Accordion title="Option 2: Siloed content access" description="Creates a completely isolated experience without shared content">
               When implemented, users can build off their assigned extension but will not see any shared instances or content from the parent level.

               **To implement this approach**, grant explicit access only to the specific child extension (e.g., `Customer 3`) and set the **parent** model to **No Access**.
             </Accordion>
           </AccordionGroup>
  </Step>

  <Step title="Testing access with user impersonation" titleSize="h3">
    To verify that your access controls are working as expected, we recommend [impersonating a test user](/administration/users/settings#impersonating-a-user).

    1. Navigate to your user list and select a test user.
    2. Change their user attribute to the extension you wish to test.
    3. Use the **Impersonate** feature to view the **Omni instance** through their eyes.
    4. Verify that the topics, tables, and metrics match the expected siloed or shared configuration.

    <Tip>
      Manage user permissions at scale by using the [Omni API](/api) or [user groups](/administration/users/groups).
    </Tip>
  </Step>
</Steps>

## Applying changes to extended models

Changes to a parent model propagate to all extensions automatically. Changes to a child extension stay within that extension only.

| I want to...                   | Do this                                                                                                                                                   |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Apply global changes           | Modify the parent **model**. Any updates—such as removing a join or adding a shared metric—will automatically propagate to **all** extensions once saved. |
| Apply changes to one extension | Edit the specific child **extension**. Actions like hiding a sensitive table or customizing a metric stay siloed within that extension.                   |

## Troubleshooting

If users are seeing incorrect data or `No Access` errors, check the following:

<AccordionGroup>
  <Accordion title="User sees parent model, not extension">
    * **Potential cause**: Incorrect attribute reference in model file
    * **Solution**: Verify the user attribute **reference** (ex: `my_user_attribute`) matches the exact string in **Settings > Attributes**.
  </Accordion>

  <Accordion title="User sees 'No Access' error">
    * **Potential cause**: Attribute value does not match any mapping
    * **Solution**: Check the user's attribute value against the `mappings` keys in the model YAML file
  </Accordion>

  <Accordion title="Changes not appearing in extension">
    * **Potential cause**: Parent model changes not saved
    * **Solution**: Ensure you have clicked **Save** in the parent model. Changes flow downstream automatically.
  </Accordion>

  <Accordion title="Extension data looks like parent data">
    * **Potential cause**: Extension-specific overrides are missing
    * **Solution**: Edit the extension model directly to apply overrides (like hiding tables) that shouldn't affect the parent
  </Accordion>
</AccordionGroup>

## Next steps

* [Extension settings](/modeling/develop/shared-extensions/settings) - Update settings, including **Allow exploration**, after an extension model is created
* [Extension branches](/modeling/develop/shared-extensions/extension-branches) - Enable isolated branches on extension models so teams can develop and test changes without affecting the parent model
