Snowflake
Set up the Snowflake destination connector.
Sync modes, namespaces and the columns Pipeloom adds are explained once in Connector concepts; workspace variables and custom components in Orchestration.
Setting up the Snowflake destination takes two parts: creating a warehouse, database, user and role for Pipeloom in Snowflake, then creating the destination in Pipeloom.
The Snowflake destination connector:
- Writes each stream into a typed table in the schema you choose.
- Supports every sync mode, including deduplication.
- Maps each source namespace to a Snowflake schema, and creates schemas as needed.
:::warning Use key pair authentication Snowflake is phasing out single-factor password sign-ins (Snowflake's announcement), enforcing strong authentication account by account between August and October 2026. Once it's enforced on your account, a destination that signs in with a username and password stops working. Use key pair authentication, as described below. :::
Before you start
You need a Snowflake account with the ACCOUNTADMIN role. If you don't have one, ask your Snowflake administrator to set one up for you.
Step 1: Create a key pair
Key pair authentication uses an RSA key pair (2048 bits or more) instead of a password. If you don't have one yet, create one with the openssl command line tool. For the details, see Snowflake's key pair authentication docs.
Create a private key
In a terminal, run one of these commands. Each writes a private key in PKCS#8 PEM format.
Unencrypted key (simpler; no passphrase needed when connecting):
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocryptEncrypted key (recommended for production; the key file is protected by a passphrase):
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes-256-cbc -inform PEM -out rsa_key.p8Encrypted keys made with -v2 des3, as Snowflake documents, work too, as do the other key formats and algorithms Snowflake supports (see Snowflake's docs for the list). You can also set up key rotation to replace keys without downtime.
:::tip Snowflake recommends an encrypted private key, with a passphrase that meets your organization's security standards. Keep the passphrase somewhere safe. :::
Create the matching public key
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pubKeep the keys safe
Copy both files to a secure local directory and restrict access to the private key file. You're responsible for keeping the key secure while it isn't in use.
If key pair sign-in doesn't work, see Snowflake's troubleshooting docs.
Step 2: Create a warehouse, database, user and role for Pipeloom
Give Pipeloom its own warehouse, database, service user and role. The role gets OWNERSHIP so it can write data, and keeping everything separate lets you track Pipeloom's costs and control its permissions precisely.
-
Open a new worksheet and paste the script below. Rename the objects if you like, and replace
<public_key_value>with the public key from Step 1.Note: new names must follow Snowflake's identifier rules.
-- set variables (these need to be uppercase)
set pipeloom_role = 'PIPELOOM_ROLE';
set pipeloom_username = 'PIPELOOM_USER';
set pipeloom_warehouse = 'PIPELOOM_WAREHOUSE';
set pipeloom_database = 'PIPELOOM_DATABASE';
set pipeloom_schema = 'PIPELOOM_SCHEMA';
begin;
-- create the Pipeloom role
use role securityadmin;
create role if not exists identifier($pipeloom_role);
grant role identifier($pipeloom_role) to role SYSADMIN;
-- create the Pipeloom service user with key pair authentication
create user if not exists identifier($pipeloom_username)
type = service
default_role = $pipeloom_role
default_warehouse = $pipeloom_warehouse;
grant role identifier($pipeloom_role) to user identifier($pipeloom_username);
-- assign the RSA public key to the service user
-- Replace <public_key_value> with the contents of your rsa_key.pub file (excluding the
-- -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- header/footer lines).
alter user identifier($pipeloom_username) set rsa_public_key='<public_key_value>';
-- change role to sysadmin for warehouse / database steps
use role sysadmin;
-- create the Pipeloom warehouse
create warehouse if not exists identifier($pipeloom_warehouse)
warehouse_size = xsmall
warehouse_type = standard
auto_suspend = 60
auto_resume = true
initially_suspended = true;
-- create the Pipeloom database
create database if not exists identifier($pipeloom_database);
-- grant warehouse access
grant USAGE
on warehouse identifier($pipeloom_warehouse)
to role identifier($pipeloom_role);
-- grant database access
grant OWNERSHIP
on database identifier($pipeloom_database)
to role identifier($pipeloom_role);
commit;- Run the script from the worksheet or Snowsight. In the Classic Console, tick All Queries; in Snowsight, select the whole script first.
:::info
Pipeloom creates the schemas it needs in the destination database, so the user needs CREATE SCHEMA on that database. You can create schemas yourself instead, but then the user needs OWNERSHIP on them, so it can manage the tables and other objects it writes.
:::
:::info Keeping costs down
Snowflake bills compute per second, and the warehouse resumes, and bills, each time Pipeloom loads data. We recommend a dedicated X-Small warehouse that suspends after one minute idle: the smallest compute size, shut down soon after each load. The script above already sets this up (warehouse_size = xsmall, auto_suspend = 60).
:::
Step 3: Check network policies
By default, Snowflake accepts connections from any IP address. A security administrator (the SECURITYADMIN role or higher) can create a network policy that allows or blocks specific addresses. If one applies to your account or to Pipeloom's user, it must allow Pipeloom to connect.
To check whether a network policy is set, run SHOW PARAMETERS:
For the account
SHOW PARAMETERS LIKE 'network_policy' IN ACCOUNT;For a user
SHOW PARAMETERS LIKE 'network_policy' IN USER <username>;See Snowflake's network policy docs for more.
Step 4: Data loading
Pipeloom loads data through Snowflake's internal stage. Make sure the role has the USAGE privilege on the database and schema.
Step 5: Create the Snowflake destination in Pipeloom
Create a new destination and choose Snowflake. You can do this from the Destinations page, or from a Destination step on a pipeline canvas. Sign in with the private key from Step 1.
-
Host: your Snowflake account's host, ending in
snowflakecomputing.com. Useaccountname.snowflakecomputing.com, or for accounts with a region-based locator,accountname.region.cloud.snowflakecomputing.com. Example:accountname.us-east-2.aws.snowflakecomputing.com -
Role: the role you created in Step 2. Example:
PIPELOOM_ROLE -
Warehouse: the warehouse you created in Step 2. Example:
PIPELOOM_WAREHOUSE -
Database: the database you created in Step 2. Example:
PIPELOOM_DATABASE -
Default Schema: the schema used for any stream that doesn't name its own.
-
Username: the service user you created in Step 2. Example:
PIPELOOM_USER -
Authorization Method: choose Key Pair Authentication.
- Private Key: paste the whole of
rsa_key.p8, including the-----BEGIN ... PRIVATE KEY-----and-----END ... PRIVATE KEY-----lines. - Passphrase: the key's passphrase, if you created an encrypted key. Leave it empty for an unencrypted key.
Username and Password (Deprecated) is still offered for existing destinations, but it will be removed, and Snowflake is blocking password-only sign-ins (see the warning at the top). If a destination still uses a password, create a key pair as in Step 1, assign its public key to the user with
alter user <username> set rsa_public_key='<public_key_value>';(see Step 2), and switch the destination to Key Pair Authentication. - Private Key: paste the whole of
Optional settings:
-
CDC deletion mode: what happens here when a row is deleted in a source that uses change data capture. Hard delete (the default) deletes the row here too; Soft delete keeps it as a tombstone record that marks it as deleted.
-
JDBC URL Params: extra connection properties, as
key=valuepairs separated by&. Example:key1=value1&key2=value2&key3=value3 -
Legacy raw tables: write only the legacy raw-table format, for compatibility with older setups. See Output tables. The format of
_airbyte_datais fairly stable, but the other metadata columns may change. -
Internal table dataset name: the schema for the connector's internal tables, and for raw tables in legacy raw-tables mode. Defaults to
airbyte_internal. -
Trim Whitespace from String Fields: on by default, so Snowflake trims leading and trailing whitespace from text as it loads. Turn it off if that whitespace is meaningful and should be kept.
-
Data Retention Period (days): how many days of Snowflake Time Travel to keep for the tables. Defaults to
1. A nonzero value adds storage costs in Snowflake. -
Decimal Data Type: the Snowflake type for decimal number columns. NUMBER(38,9) (recommended) stores values exactly, which suits money and other exact decimals. FLOAT (the default) stores them approximately, which suits scientific values and very large magnitudes. See Decimal numbers. If you change it on an existing destination, clear the sync's data so the next run copies everything again.
Save the destination. Pipeloom tests the connection, and the destination is ready once the test passes.
Output tables
Each stream is written to a final table with typed columns. The connector also keeps a raw table per stream, in the airbyte_internal schema unless you set a different Internal table dataset name. Raw tables aren't deduplicated.
:::info The connector creates permanent tables. If you prefer transient tables, give Pipeloom a transient database: every table created in it is then transient, which avoids the extra cost and storage of Fail-safe. Transient tables can't be recovered after an operational or system failure.
If you set a custom internal schema, keep it and the default schema in databases of the same kind (both transient or both permanent), so both get the same data protection. See Working with Temporary and Transient Tables. :::
Raw table columns
_airbyte_raw_id_airbyte_generation_id_airbyte_extracted_at_airbyte_loaded_at_airbyte_meta_airbyte_data
_airbyte_data holds the record as JSON. See metadata columns for the others.
:::info
The contents of _airbyte_data are fairly stable, but the raw table's columns may change.
:::
Final table columns
Besides the columns in your stream's schema, each final table has:
_AIRBYTE_RAW_ID_AIRBYTE_GENERATION_ID_AIRBYTE_EXTRACTED_AT_AIRBYTE_LOADED_AT_AIRBYTE_META
See metadata columns for what they hold.
Data type mapping
| Source type | Snowflake type |
|---|---|
| STRING | TEXT |
| STRING (BASE64) | TEXT |
| STRING (BIG_NUMBER) | TEXT |
| STRING (BIG_INTEGER) | TEXT |
| NUMBER | FLOAT (default) or NUMBER(38,9) |
| INTEGER | NUMBER |
| BOOLEAN | BOOLEAN |
| STRING (TIMESTAMP_WITH_TIMEZONE) | TIMESTAMP_TZ |
| STRING (TIMESTAMP_WITHOUT_TIMEZONE) | TIMESTAMP_NTZ |
| STRING (TIME_WITH_TIMEZONE) | TEXT |
| STRING (TIME_WITHOUT_TIMEZONE) | TIME |
| DATE | DATE |
| OBJECT | OBJECT |
| ARRAY | ARRAY |
| UNION | VARIANT |
| UNKNOWN | VARIANT |
Decimal numbers
The Decimal Data Type setting picks the Snowflake type for decimal number columns:
- NUMBER(38,9) (recommended): an exact fixed-point decimal, with up to 29 digits before the decimal point and 9 after it. Use it for financial data and anything else that needs exact decimals within that range.
- FLOAT (the default): an approximate binary floating-point number with about 15 significant digits and magnitudes up to about 10^308. Use it for scientific values, statistics, model scores and very large numbers, where range matters more than exact decimals.
The setting doesn't affect:
- Legacy raw tables, which have no typed columns: every value is in the
_airbyte_dataVARIANT column. - Whole-number database types such as
NUMERIC(10,0). Sources read those as integers, which are always stored as Snowflake NUMBER.
:::warning After changing this setting on an existing destination, clear the sync's data so the next run copies everything again. Otherwise the next sync converts the existing number columns in place, and data can be lost:
- To NUMBER(38,9): stored FLOAT values with more than 29 digits before the decimal point become NULL. Snowflake converts the column in place, so these changes aren't recorded in
_airbyte_meta. Values that lost precision when they were loaded as FLOAT (flaggedTRUNCATEDin_airbyte_meta) stay imprecise; only a full re-copy brings back the source values. - To FLOAT: values become approximate again, and query results may differ slightly. :::
Precision and size limits
Snowflake limits numeric precision:
- FLOAT: a standard 64-bit floating point value, about 15 significant digits.
- NUMBER(38,9) (if you chose it for decimals): at most 29 digits before the decimal point. Larger values are set to null and flagged in
_airbyte_meta; if your data has values that large, use FLOAT. Digits beyond 9 decimal places are truncated and flagged in_airbyte_meta. - NUMBER (used for integers): at most 38 digits.
A value outside these bounds is set to null. A value within bounds but with too much precision is rounded. Either way, the record's _airbyte_meta column gets a changes entry saying so.
Snowflake also limits the size of text and semi-structured values:
- VARCHAR: at most 16 MB (UTF-8 encoded).
- VARIANT (used for OBJECT, ARRAY, UNION and UNKNOWN): at most 128 MB.
Larger values are set to null, and _airbyte_meta records the change.
Schema changes
When the source schema changes, the connector updates the destination tables: it adds new columns and changes column types as needed. When a column is removed from the source, the connector keeps the column and the data it already holds in the destination table, and writes NULL to it for new rows. The user needs ALTER TABLE on the destination tables for this.
Column names that are ANSI SQL reserved keywords (such as SELECT or ORDER) get an underscore in front (_SELECT, _ORDER).
Sync modes
This destination supports every sync mode:
| Sync mode | Supported |
|---|---|
| Full refresh overwrite | Yes |
| Full refresh overwrite deduped | Yes |
| Full refresh append | Yes |
| Incremental append | Yes |
| Incremental append deduped | Yes |
:::note In Legacy raw tables mode nothing is deduplicated: sync modes that would deduplicate append to the raw table instead. :::
It supports namespaces: each namespace maps to a Snowflake schema.
Troubleshooting
Current role does not have permissions on the target schema
The role in the destination's settings doesn't have permissions on the schema being written to. This often happens when a sync's Destination Namespace is set to use the source's schemas (Source-defined, or Mirror source structure), which can make it write to a schema such as PUBLIC that the role can't use.
Either switch the sync's Destination Namespace to the destination's default schema (Destination-defined, or Destination default), or grant the role the permissions it needs on the schema it's writing to.