> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/references/v1/resources/nilus/roles-and-permissions/snowflake-minimum-permissions.md).

# Snowflake

This page lists the minimum Snowflake grants required to run each Nilus pipeline mode against a Snowflake depot. Use it as a provisioning reference when granting access to a Nilus pipeline role and user.

## Read data: Snowflake as source (type: batch)

Used when the depot is referenced in `source.address` of a Nilus pipeline config. Nilus issues `SELECT` queries (full scan or incremental via a cursor column) against the target table.

### Minimum grants

```sql
-- Step 1: Create role and user
CREATE ROLE nilus_reader_role;

CREATE USER nilus_reader_user
    DEFAULT_ROLE = nilus_reader_role
    PASSWORD = '<password>';

GRANT ROLE nilus_reader_role TO USER nilus_reader_user;

-- Step 2: Warehouse (required to execute any query)
GRANT USAGE ON WAREHOUSE <warehouse_name> TO ROLE nilus_reader_role;

-- Step 3: Database
GRANT USAGE ON DATABASE <database_name> TO ROLE nilus_reader_role;

-- Step 4: Schemas: existing and future
GRANT USAGE ON ALL SCHEMAS IN DATABASE <database_name> TO ROLE nilus_reader_role;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE <database_name> TO ROLE nilus_reader_role;

-- Step 5: Tables and views: existing and future
GRANT SELECT ON ALL TABLES IN DATABASE <database_name> TO ROLE nilus_reader_role;
GRANT SELECT ON FUTURE TABLES IN DATABASE <database_name> TO ROLE nilus_reader_role;
GRANT SELECT ON ALL VIEWS IN DATABASE <database_name> TO ROLE nilus_reader_role;
GRANT SELECT ON FUTURE VIEWS IN DATABASE <database_name> TO ROLE nilus_reader_role;
```

{% hint style="info" %}
To restrict access to a single schema, replace `IN DATABASE <database_name>` with `ON SCHEMA <schema_name> IN DATABASE <database_name>` in each grant.
{% endhint %}

## Write data: Snowflake as destination (type: batch)

Used when the depot is referenced in `sink.address` of a Nilus pipeline config. Nilus manages table creation and data loading. The required grants depend on the `incremental_strategy` in use.

### Schema creation

If the destination schema does not exist yet, Nilus creates it during the pipeline run. Creating a schema requires the database-level `CREATE SCHEMA` privilege, granted with `GRANT CREATE SCHEMA ON DATABASE`. Snowflake does not support granting `CREATE SCHEMA` at the schema level.

{% hint style="warning" %}
Without the `CREATE SCHEMA` grant, the pipeline fails on the first write to a schema that has not been pre-created.
{% endhint %}

### Minimum grants (covers all strategies)

```sql
-- Step 1: Create role and user
CREATE ROLE nilus_writer_role;

CREATE USER nilus_writer_user
    DEFAULT_ROLE = nilus_writer_role
    PASSWORD = '<password>';

GRANT ROLE nilus_writer_role TO USER nilus_writer_user;

-- Step 2: Warehouse
GRANT USAGE ON WAREHOUSE <warehouse_name> TO ROLE nilus_writer_role;

-- Step 3: Database
GRANT USAGE ON DATABASE <database_name> TO ROLE nilus_writer_role;

-- Step 4: Schema creation (required if schema may not exist)
GRANT CREATE SCHEMA ON DATABASE <database_name> TO ROLE nilus_writer_role;

-- Step 5: Schema access: existing and future
GRANT USAGE ON ALL SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;

-- Step 6: Table creation: existing and future schemas
GRANT CREATE TABLE ON ALL SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;
GRANT CREATE TABLE ON FUTURE SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;

-- Step 6b: Stage creation (Nilus/dlt bulk-loads through Snowflake internal stages)
GRANT CREATE STAGE ON ALL SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;
GRANT CREATE STAGE ON FUTURE SCHEMAS IN DATABASE <database_name> TO ROLE nilus_writer_role;

-- Step 7: DML on existing and future tables
GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
    ON ALL TABLES IN DATABASE <database_name> TO ROLE nilus_writer_role;
GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE
    ON FUTURE TABLES IN DATABASE <database_name> TO ROLE nilus_writer_role;
```

### Grants by incremental strategy

| Strategy  | Required DML                                                                                                                 |
| --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `append`  | `INSERT`, `CREATE TABLE`, `CREATE STAGE`, `CREATE SCHEMA` (if schema may not exist)                                          |
| `merge`   | `INSERT`, `UPDATE`, `DELETE`, `SELECT`, `CREATE TABLE`, `CREATE STAGE`, `CREATE SCHEMA`                                      |
| `replace` | `INSERT`, `TRUNCATE`, `DROP TABLE` (implicit via `CREATE OR REPLACE TABLE`), `CREATE TABLE`, `CREATE STAGE`, `CREATE SCHEMA` |

## Hera metadata ingestion: Snowflake source connector (type: metadata)

Used when the depot is referenced in `source.address` of a `type: metadata` Nilus pipeline. Nilus drives the Hera Snowflake source connector, resolving the depot to a `metadata+snowflake://` URI internally.

### Basic metadata (tables, schemas, columns, tags)

```sql
-- Step 1: Create role and user
CREATE ROLE hera_ingestion_role;

CREATE USER hera_ingestion_user
    DEFAULT_ROLE = hera_ingestion_role
    PASSWORD = '<password>';

GRANT ROLE hera_ingestion_role TO USER hera_ingestion_user;

-- Step 2: Warehouse
GRANT USAGE ON WAREHOUSE <warehouse_name> TO ROLE hera_ingestion_role;

-- Step 3: Database
GRANT USAGE ON DATABASE <database_name> TO ROLE hera_ingestion_role;

-- Step 4: Schemas: existing and future
GRANT USAGE ON ALL SCHEMAS IN DATABASE <database_name> TO ROLE hera_ingestion_role;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE <database_name> TO ROLE hera_ingestion_role;

-- Step 5: All object types that Hera enumerates
GRANT SELECT ON ALL TABLES IN DATABASE <database_name>             TO ROLE hera_ingestion_role;
GRANT SELECT ON FUTURE TABLES IN DATABASE <database_name>          TO ROLE hera_ingestion_role;
GRANT SELECT ON ALL VIEWS IN DATABASE <database_name>              TO ROLE hera_ingestion_role;
GRANT SELECT ON FUTURE VIEWS IN DATABASE <database_name>           TO ROLE hera_ingestion_role;
GRANT SELECT ON ALL EXTERNAL TABLES IN DATABASE <database_name>    TO ROLE hera_ingestion_role;
GRANT SELECT ON FUTURE EXTERNAL TABLES IN DATABASE <database_name> TO ROLE hera_ingestion_role;
GRANT SELECT ON ALL DYNAMIC TABLES IN DATABASE <database_name>     TO ROLE hera_ingestion_role;
GRANT SELECT ON FUTURE DYNAMIC TABLES IN DATABASE <database_name>  TO ROLE hera_ingestion_role;
```

### Additional grants by workflow type

| Workflow                                                           | Extra grant required                                                                                                   | What it accesses                                      |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| **Lineage and usage**                                              | `GRANT IMPORTED PRIVILEGES ON ALL SCHEMAS IN DATABASE SNOWFLAKE TO ROLE hera_ingestion_role;`                          | `snowflake.account_usage.query_history`               |
| **Tags ingestion**                                                 | Same `IMPORTED PRIVILEGES` above                                                                                       | `snowflake.account_usage.tag_references`              |
| **Stored procedures**                                              | Same `IMPORTED PRIVILEGES` above                                                                                       | `snowflake.account_usage.procedures` and `.functions` |
| **Incremental extraction**                                         | Same `IMPORTED PRIVILEGES` above                                                                                       | `snowflake.account_usage.tables`                      |
| **Column-level lineage** (masking or row-access policies on views) | `GRANT APPLY MASKING POLICY TO ROLE hera_ingestion_role;` `GRANT APPLY ROW ACCESS POLICY TO ROLE hera_ingestion_role;` | Policy definitions on view DDLs                       |

```sql
-- Grant for lineage, usage, tags, stored procedures, and incremental extraction
GRANT IMPORTED PRIVILEGES ON ALL SCHEMAS IN DATABASE SNOWFLAKE TO ROLE hera_ingestion_role;
```

{% hint style="info" %}
If direct access to `SNOWFLAKE.ACCOUNT_USAGE` is restricted, replicate the required tables (`QUERY_HISTORY`, `TAG_REFERENCES`, `PROCEDURES`, `FUNCTIONS`) to a custom schema, then set the `Account Usage Schema Name` option in the Hera connector to point to it (for example, `CUSTOM_DB.CUSTOM_SCHEMA`).
{% endhint %}

## Permission matrix

| Use case                  | `USAGE` WH | `USAGE` DB | `USAGE` Schema | `SELECT` | `INSERT` | `UPDATE/DELETE` | `CREATE SCHEMA` | `CREATE TABLE` | `CREATE STAGE` | Account Usage |
| ------------------------- | ---------- | ---------- | -------------- | -------- | -------- | --------------- | --------------- | -------------- | -------------- | ------------- |
| Read (source, batch)      | Yes        | Yes        | Yes            | Yes      | No       | No              | No              | No             | No             | No            |
| Write, `append`           | Yes        | Yes        | Yes            | No       | Yes      | No              | Yes             | Yes            | Yes            | No            |
| Write, `merge`            | Yes        | Yes        | Yes            | Yes      | Yes      | Yes             | Yes             | Yes            | Yes            | No            |
| Write, `replace`          | Yes        | Yes        | Yes            | No       | Yes      | TRUNCATE        | Yes             | Yes (+ DROP)   | Yes            | No            |
| Hera metadata (basic)     | Yes        | Yes        | Yes            | Yes      | No       | No              | No              | No             | No             | No            |
| Hera lineage, usage, tags | Yes        | Yes        | Yes            | Yes      | No       | No              | No              | No             | No             | Yes           |

## Notes

* `role` lives in the depot secret only. The depot spec does not carry a `role` field. Set `role` in the secret to activate a specific Snowflake role for the session. If not set, Snowflake falls back to the user's `DEFAULT_ROLE`.
* The role must be pre-granted to the user before the pipeline runs.

{% hint style="warning" %}
If `role` is set in the depot secret, run `GRANT ROLE <role_name> TO USER <username>;` in Snowflake before the pipeline runs. Otherwise the connection is rejected at session activation.
{% endhint %}

* `CREATE SCHEMA` is a database-level privilege, granted with `GRANT CREATE SCHEMA ON DATABASE`, not at the schema level. Omitting this grant causes the pipeline to fail on the first write to a schema that does not yet exist.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/references/v1/resources/nilus/roles-and-permissions/snowflake-minimum-permissions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
