Skip to content

Model access control

You can restrict which users can see and query a data model by adding an access block to the model's YAML configuration. Models without an access block are visible to everyone in the account.

Basic usage

Restrict by user parameters

Use user_parameters to require that users have specific parameters assigned to them. All specified parameters must match (AND logic). When a specific property has an array of values, the user must match at least one.

yaml
models:
  salaries:
    name: Salaries

    table: hr.salaries

    access:
      user_parameters:
        department: hr
        data_level: sensitive

    properties:
      employee_id:
        name: Employee ID
        type: String
      salary:
        name: Salary
        type: Number

The user must have department=hr and data_level=sensitive to see this model.

Restrict by email

Use user_parameters.email to allow only specific users by their email address.

yaml
models:
  exec_dashboard:

    name: Executive Dashboard

    table: reporting.exec_summary

    access:
      user_parameters:
        email:
          - alice@example.com
          - bob@example.com

    properties:
      revenue:
        name: Revenue
        type: Number

Array values for OR matching

When a user parameter can have multiple acceptable values, use an array. The user's parameter must match any one of the listed values.

yaml
access:
  user_parameters:
    region:
      - eu
      - us

This grants access to users with region=eu or region=us.

Combining conditions with AND

When you specify multiple conditions at the root level of access, the user must satisfy all of them.

yaml
access:
  user_parameters:
    department: hr
    email: alice@example.com

The user must have department=hr and their email must be alice@example.com.

Creating exceptions with any

Use the any block when you want to grant access if the user matches at least one of the conditions. This is useful for creating exceptions — for example, allowing a specific user to access a model without assigning them all the required parameters.

yaml
models:
  salaries:
    name: Salaries

    table: hr.salaries

    access:
      any:
        user_parameters:
          department: hr
          email: special-snowflake@example.com

    properties:
      employee_id:
        name: Employee ID
        type: String

The user has department=hr or is special-snowflake@example.com.

Combining AND and OR

Root-level conditions and any can be combined. Root-level conditions are AND-ed together, any conditions are OR-ed, and the two groups are AND-ed with each other: (root conditions) AND (any conditions).

yaml
models:
  sensitive_salaries:
    name: Sensitive Salaries
    table: hr.salaries_sensitive
    access:
      user_parameters:
        data_level: sensitive
      any:
        user_parameters:
          department: hr
          email:
            - special-snowflake@example.com
    properties:
      employee_id:
        name: Employee ID
        type: String

The user must have data_level=sensitive and either department=hr or be special-snowflake@example.com.

Derived models

Derived models inherit the access block from their base model by default. You can override this by defining access on the derived model — this replaces the base model's access entirely (it does not merge).

yaml
models:
  salaries:
    name: Salaries
    table: hr.salaries
    access:
      user_parameters:
        department: hr
    properties:
      employee_id:
        name: Employee ID
        type: String

  salaries_public:
    name: Salaries (Public)
    base_model: salaries
    access: {}

An empty access: {} makes the derived model visible to everyone, regardless of the base model's restrictions.

Row-level security

In addition to controlling which users can see a model, you can filter the data within a model based on user properties. Use the {{user_parameters.<key>}} placeholder in your model's sql definition to inject the current user's property values into the query at runtime.

Basic example

yaml
models:
  orders:
    name: Orders

    sql: |-
      SELECT * FROM orders
      WHERE region IN ({{user_parameters.region}})

    properties:
      order_id:
        name: Order ID
        type: String
      region:
        name: Region
        type: String

For a user with the property region set to eu, the query becomes:

sql
SELECT * FROM public.orders WHERE region IN ('eu')

Multiple values

When a user has multiple values for a property (for example, from belonging to multiple user groups), all values are included as a comma-separated list.

For a user with region values eu and us:

sql
SELECT * FROM public.orders WHERE region IN ('eu', 'us')

Missing properties

If the user does not have the referenced property, the placeholder is replaced with NULL. Since IN (NULL) matches no rows in SQL, the query returns no results.

sql
SELECT * FROM public.orders WHERE region IN (NULL)

Combining with model access control

Row-level security and model-level access control work independently. You can use both on the same model — the access block controls who can see the model, while {{user_parameters.*}} controls which rows they see.

yaml
models:
  regional_orders:
    name: Regional Orders

    sql: |-
      SELECT * FROM orders
      WHERE region IN ({{user_parameters.region}})

    access:
      user_parameters:
        department: sales

    properties:
      order_id:
        name: Order ID
        type: String

Only users with department=sales can see this model, and each user only sees orders matching their region property.

What happens when a model is hidden

When a user does not satisfy a model's access conditions:

  • The model does not appear in model listings or the explore UI
  • Queries referencing the model as baseModelId fail with insufficient privileges error
  • Relations pointing to the hidden model are not available
  • Metrics based on the hidden model are not visible
  • Derived models that inherit the base model's access are also hidden