> ## Documentation Index
> Fetch the complete documentation index at: https://www.qovery.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Snowflake Database

> Provision a Snowflake database, schema, warehouse and application role, with an optional SERVICE user and generated key pair so an application on any cloud — AWS, Azure, Scaleway or GCP — can connect

Qovery creates it in your account with a third-party provider, using credentials you enter in the form, as a [Blueprint](https://www.qovery.com/docs/configuration/blueprints.md) service in one of your environments.

| | |
| - | - |
| Catalog name | `snowflake-database` |
| Category | Analytics |
| Provider | EXTERNAL |
| Engine | terraform |
| Major versions (latest release) | `default` (1.0.3) |
| Source | [EXTERNAL/snowflake/default](https://github.com/Qovery/service-catalog/tree/EXTERNAL/snowflake/default/1.0.3/EXTERNAL/snowflake/default) |

> [!TIP]
>
> **New to this?** You don't need to know Terraform or Kubernetes. Qovery sets up Snowflake Database in your account with the provider: you fill in a form, or paste the prompt below into your coding agent. The values it publishes, listed under Outputs, reach your other services as environment variables. Qovery tells you when a newer version of the Blueprint is available. Check the requirements in the Reference section before you start, and try it first in a development environment.

## Create it

> [tab] Console
>
> 1. Open the environment, then **New service** › **Blueprint**.
> 2. Find **Snowflake Database** in the catalog and pick the major version.
> 3. Fill in the variables. Required ones are marked; the others use their defaults.
> 4. Create the service, and deploy it now or later.

> [tab] CLI and API
>
> List the catalog to get the latest tag, then create the service from it. `qovery api` signs the requests with your CLI session.
>
> ```bash theme={null}
> ORG_ID="REPLACE_WITH_ORGANIZATION_ID"
> ENV_ID="REPLACE_WITH_ENVIRONMENT_ID"
>
> qovery api "organization/$ORG_ID/blueprint/catalog" | jq '.. | objects | select(.name? == "snowflake-database")'
>
> cat > blueprint.json <<'EOF'
> {
>   "name": "snowflake-database",
>   "tag": "EXTERNAL/snowflake/default/1.0.3",
>   "icon": "app://qovery-console/snowflake",
>   "variables": [
>     {
>       "name": "snowflake_organization_name",
>       "value": "REPLACE_WITH_SNOWFLAKE_ORGANIZATION_NAME"
>     },
>     {
>       "name": "snowflake_account_name",
>       "value": "REPLACE_WITH_SNOWFLAKE_ACCOUNT_NAME"
>     },
>     {
>       "name": "snowflake_user",
>       "value": "REPLACE_WITH_SNOWFLAKE_USER"
>     },
>     {
>       "name": "snowflake_private_key",
>       "value": "REPLACE_WITH_SNOWFLAKE_PRIVATE_KEY",
>       "is_secret": true
>     },
>     {
>       "name": "database_name",
>       "value": "REPLACE_WITH_DATABASE_NAME"
>     }
>   ],
>   "spec_overrides": {
>     "engine_version": "1.9.7"
>   }
> }
> EOF
> BLUEPRINT_ID=$(qovery api "environment/$ENV_ID/blueprint" --method POST --input - < blueprint.json | jq -r .id)
> rm blueprint.json   # it can hold secret values
> qovery api "blueprint/$BLUEPRINT_ID/deploy" --method POST
> qovery api "blueprint/$BLUEPRINT_ID"   # status of the latest deployment
> ```
>
> Replace each `REPLACE_WITH_` value. Add optional variables to `variables` the same way.

> [tab] Coding agent
>
> Paste this into Claude Code, Cursor, Codex or another coding agent with the [Qovery agent skills](https://www.qovery.com/docs/getting-started/quickstart/agent-skills.md) installed (`curl -fsSL https://skill.qovery.com/install.sh | bash`).
>
> ```text Prompt wrap theme={null}
> Add the Qovery Blueprint Snowflake Database (snowflake-database) to one of my Qovery environments and deploy it. Ask me for snowflake_organization_name, snowflake_account_name, snowflake_user, snowflake_private_key and database_name.
> Ask me before deploying to a production environment.
> Docs: https://www.qovery.com/docs/configuration/blueprints/snowflake-database.md
> ```

You don't add any file to your repository. Qovery creates the Blueprint from the Console or the API.

## Variables and outputs

Generated from `qbm.yml` at `EXTERNAL/snowflake/default/1.0.3`, the manifest the Console form is built from.

> [accordion] All 19 variables
>
> | Name | Type | Required | Default | Secret | Description |
> | - | - | - | - | - | - |
> | `snowflake_organization_name` | string | Yes | | | First half of the account identifier (the ORGNAME in ORGNAME-ACCOUNTNAME) |
> | `snowflake_account_name` | string | Yes | | | Second half of the account identifier (ORGNAME-ACCOUNTNAME), not the legacy account locator |
> | `snowflake_user` | string | Yes | | | Snowflake user Terraform authenticates as. Its RSA public key must already be registered on the user. |
> | `snowflake_private_key` | string | Yes | | Yes | PEM-encoded PKCS#8 private key matching the public key registered on snowflake\_user |
> | `snowflake_private_key_passphrase` | string | | | Yes | Passphrase protecting snowflake\_private\_key. Empty = the key is unencrypted. |
> | `snowflake_role` | string | | `ACCOUNTADMIN` | | Role Terraform runs as. It must be able to create databases, warehouses, roles and users, and to grant them — SYSADMIN alone cannot create a role. |
> | `database_name` | string | Yes | | | Upper-cased, so it stays an unquoted identifier. Max 246 chars: derived warehouse, role and user names append up to 9 more. |
> | `schema_name` | string | | `APP` | | Schema created inside the database. Upper-cased before use. |
> | `warehouse_name` | string | | | | Leave empty — derived from the database name as \<database\_name>\_WH. Set it only to match an existing naming convention. |
> | `warehouse_size` | string | | `XSMALL` | | Warehouse size; each step up doubles the credit burn |
> | `auto_suspend_seconds` | number | | `60` | | Idle seconds before the warehouse suspends. This is the main cost control: a warehouse bills for every second it stays up. |
> | `data_retention_time_in_days` | number | | `1` | | Time Travel window on the database, in days. Above 1 requires Enterprise Edition; 0 disables Time Travel and with it UNDROP. |
> | `role_name` | string | | | | Leave empty — derived from the database name as \<database\_name>\_APP. This is the account role holding the grants. |
> | `schema_privileges` | string | | `USAGE,CREATE TABLE,CREATE VIEW,CREATE STAGE` | | Comma-separated privileges granted to the role on the schema itself |
> | `table_privileges` | string | | `SELECT,INSERT,UPDATE,DELETE` | | Comma-separated privileges granted to the role on future tables in the schema |
> | `grant_future_table_privileges` | bool | | `true` | | Grant table\_privileges on future tables in the schema. Set false to manage table grants yourself. |
> | `create_service_user` | bool | | `true` | | Create a SERVICE user with a generated RSA key pair and the role, for apps on any cloud. Turn off to attach your own users to the role. |
> | `service_user_name` | string | | | | Leave empty — derived from the database name as \<database\_name>\_APP\_USER. Only used when create\_service\_user is true. |
> | `grant_role_to_user` | string | | | | Existing Snowflake user to also grant the role to. Unset = grant it to nobody beyond the created service user. |

Outputs become environment variables that other services in the environment can use. By default Qovery also creates an alias for each output, prefixed with the Blueprint's name; see [Aliases Qovery creates for outputs](https://www.qovery.com/docs/configuration/environment-variables.md#aliases-qovery-creates-for-outputs) for the naming rules and the cases where no alias is created.

> [accordion] All 9 outputs
>
> | Name | Secret | Description |
> | - | - | - |
> | `account_identifier` | | Account identifier (ORGNAME-ACCOUNTNAME) |
> | `account_url` | | Account URL to connect to |
> | `database_name` | | Database created by this blueprint |
> | `schema_name` | | Schema created inside the database |
> | `warehouse_name` | | Warehouse created by this blueprint |
> | `role_name` | | Account role holding the grants on the database, schema and warehouse |
> | `service_user_name` | | SERVICE user granted the role (empty when create\_service\_user is false) |
> | `service_user_private_key` | Yes | PEM PKCS#8 key of the SERVICE user, for Snowflake key-pair auth |
> | `jdbc_url` | | JDBC URL preset to the created database, schema, warehouse and role |

> [!WARNING]
>
> Secret variables and outputs are encrypted and masked in Qovery, but Terraform can also keep their values, and values derived from them, in its state. With the Qovery-managed state backend (the default), Qovery stores the state. If you use your own backend, protect it and keep state files out of version control.

## Reference

From the Blueprint's [README](https://github.com/Qovery/service-catalog/blob/EXTERNAL/snowflake/default/1.0.3/EXTERNAL/snowflake/default/README.md).

Provisions a [Snowflake](https://www.snowflake.com/) database, schema, warehouse and application
role with its grants (`snowflake_database`, `snowflake_schema`, `snowflake_warehouse`,
`snowflake_account_role`, `snowflake_grant_privileges_to_account_role`) and, by default, a `SERVICE`
user with a generated RSA key pair (`snowflake_service_user`, `tls_private_key`), via the official
`snowflakedb/snowflake` provider (`~> 2.0`).

**Available on every cloud.** This is an `EXTERNAL` blueprint: it authenticates with Snowflake
account credentials supplied as variables, never with the cluster's cloud identity, so it deploys
the same way from an AWS, Azure, Scaleway or GCP cluster. The generated key pair is what lets a
workload anywhere authenticate to Snowflake.

### Credentials

Key-pair (JWT) auth: `snowflake_organization_name`, `snowflake_account_name`, `snowflake_user` and
`snowflake_private_key` (sensitive), supplied as variables (`credentials.default: env`). The public
half must already be registered on that user:

```sql theme={null}
ALTER USER TERRAFORM_USER SET RSA_PUBLIC_KEY='MIIBIjANBg...';
```

Password auth is deliberately not offered — Snowflake blocks it outright for `SERVICE` users and is
retiring single-factor password sign-in, so it is the one credential shape guaranteed to break.

`snowflake_role` (default `ACCOUNTADMIN`) is the role Terraform runs as. It needs `CREATE DATABASE`,
`CREATE WAREHOUSE`, `CREATE ROLE` and `CREATE USER` on the account plus the right to grant them;
`SYSADMIN` alone cannot create a role, which is why the default is not `SYSADMIN`.

### Variables

#### Required

| Name | Type | Sensitive | Description |
| - | - | - | - |
| `snowflake_organization_name` | string | | Snowflake organization name — the first half of the account identifier (the ORGNAME in ORGNAME-ACCOUNTNAME) |
| `snowflake_account_name` | string | | ACCOUNTNAME half — not the legacy account locator |
| `snowflake_user` | string | | User Terraform authenticates as |
| `snowflake_private_key` | string | yes | PEM PKCS#8 private key for that user |
| `database_name` | string | | Database to create. Upper-cased before use, so it stays an unquoted Snowflake identifier. Capped at 246 chars because the derived warehouse, role and user names append up to 9 more. |

#### Optional

| Name | Type | Default | Description |
| - | - | - | - |
| `snowflake_private_key_passphrase` | string | | Passphrase for the key. Empty = unencrypted key (sensitive) |
| `snowflake_role` | string | `ACCOUNTADMIN` | Role Terraform runs as |
| `schema_name` | string | `APP` | Schema created in the database (same pattern, max 255 chars) |
| `warehouse_name` | string | | Leave empty — derived as `<database_name>_WH`. Same identifier rules if set |
| `warehouse_size` | string | `XSMALL` | Compute size of the created warehouse. Each step up doubles the credit burn per second of runtime. |
| `auto_suspend_seconds` | number | `60` | Idle seconds before suspend (60–3600). The main cost control |
| `data_retention_time_in_days` | number | `1` | Time Travel window (0–90). Above 1 needs Enterprise Edition |
| `role_name` | string | | Leave empty — derived as `<database_name>_APP`. Same identifier rules if set |
| `schema_privileges` | string | `USAGE,CREATE TABLE,CREATE VIEW,CREATE STAGE` | Comma-separated privileges on the schema |
| `table_privileges` | string | `SELECT,INSERT,UPDATE,DELETE` | Comma-separated privileges on future tables in the schema |
| `grant_future_table_privileges` | bool | `true` | Apply `table_privileges` to future tables |
| `create_service_user` | bool | `true` | Create a SERVICE user with a generated RSA key pair and grant it the role, so an application on any cloud can connect. Set false to attach your own users to the role. |
| `service_user_name` | string | | Leave empty — derived as `<database_name>_APP_USER`. Same rules if set |
| `grant_role_to_user` | string | | Existing user to also grant the role to. Unset = nobody beyond the service user |

### Outputs

| Name | Sensitive | Description |
| - | - | - |
| `account_identifier` | | `ORGNAME-ACCOUNTNAME` |
| `account_url` | | Account URL to connect to |
| `database_name` | | Database created |
| `schema_name` | | Schema created |
| `warehouse_name` | | Warehouse created |
| `role_name` | | Account role holding the grants |
| `service_user_name` | | `SERVICE` user granted the role (empty when not created) |
| `service_user_private_key` | yes | PKCS#8 private key for that user, for driver key-pair auth |
| `jdbc_url` | | JDBC URL preset to the database, schema, warehouse and role |

### Notes

* **`database_name` caps at 246, not Snowflake's 255.** The derived warehouse, role and user names
  append up to `_APP_USER`, so a 255-char database would produce a 264-char identifier that
  Snowflake rejects at apply. The cap is unconditional — setting `warehouse_name`, `role_name` and
  `service_user_name` explicitly does not lift it.
* **Identifiers are upper-cased.** Snowflake upper-cases unquoted identifiers while the provider
  creates objects exactly as named, so `mydb` would become a case-sensitive object that only
  resolves when double-quoted. Every name here goes through `upper()` to avoid that.
* **Table grants are future grants.** The schema is created by this blueprint, so every table it
  will hold is a future table at apply time. Tables that predate the deployment (only possible when
  pointing the role at an existing schema) are not covered.
* **The warehouse starts suspended** and suspends again after `auto_suspend_seconds`; the first
  query resumes it. A warehouse bills per second while it is up, so this default is the difference
  between paying for queries and paying for idle time.
* **The generated private key is a long-lived credential**, surfaced as a sensitive output and
  stored encrypted by Qovery. Rotating it means tainting `tls_private_key.app` and redeploying,
  which also updates the user's registered public key.
* **`data_retention_time_in_days` above 1 requires Enterprise Edition**; a Standard account rejects
  the apply rather than silently clamping.
* Tables and views are deliberately out of scope: their schema belongs with the application that
  owns them. Point your migration tooling at `database_name`.`schema_name`.


## Related topics

- [Blueprints](https://www.qovery.com/docs/configuration/blueprints.md)
- [Databases](https://www.qovery.com/docs/configuration/database.md)
- [qovery database](https://www.qovery.com/docs/cli/commands/database.md)
- [Create a Database](https://www.qovery.com/docs/getting-started/guides/getting-started/connect-database.md)
- [Delete a database ](https://www.qovery.com/docs/api-reference/database-main-calls/delete-a-database.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.