DEV Community

Cover image for Salesforce to Snowflake, With Less Friction: Zero-Copy V2 in Practice
Krishna Tangudu
Krishna Tangudu

Posted on

Salesforce to Snowflake, With Less Friction: Zero-Copy V2 in Practice

In Part 1, I described connecting Salesforce data to Snowflake. It worked, but the credential setup and Salesforce-style names added housekeeping before analysts could use it.

I have since tested the V2 connector. The enrollment-code handoff is simpler, authentication uses OIDC, and friendly names remove some SQL cleanup. We also kept legacy schema aliases and compared grants before and after migration to preserve existing access.

Here is the setup, what improved, and where my incremental test stopped.

The handoff is much simpler

Snowflake admin                  Salesforce admin
Create connector
Get Enrollment ID -------------> Create Snowflake V2 target
                                 Link selected Data Shares
Mount shared data <------------- Shares become available
Query with SQL
Enter fullscreen mode Exit fullscreen mode

V2 uses OpenID Connect (OIDC). For administrators, the enrollment-code flow replaces the manual credential configuration in my original walkthrough. Salesforce V2 release notes

The source is Salesforce Data Cloud, now called Data 360. CRM data must already be available there. Snowflake exposes it through a catalog-linked database without replicating the shared data into native Snowflake tables. How it works

Step 1: Create the connector and get the code

I used SQL. The example below follows that flow with generic names, using an existing administration schema:

CREATE ZEROCOPY CONNECTOR
  PLATFORM_ADMIN.ADMINISTRATION.SALESFORCE_ZC
  PARTNER = 'SALESFORCE';

SELECT SYSTEM$GET_ZEROCOPY_CONNECTOR_CONFIG(
  'PLATFORM_ADMIN.ADMINISTRATION.SALESFORCE_ZC'
);
Enter fullscreen mode Exit fullscreen mode

The returned configuration contains enrollment_code—the value the UI calls the Enrollment ID. Pass that value securely to your Salesforce administrator. Snowflake connector setup

You can also create the connector through Ingestion → Zero-Copy → Overview in Snowsight. Choose Connect on the Salesforce card; after creation, the setup panel displays the same Enrollment ID.

Your role needs the relevant database/schema access and connector privileges. In particular, creating the connector requires CREATE ZEROCOPY CONNECTOR on its schema; retrieving its configuration requires OPERATE. Privileges

Step 2: Choose what Salesforce shares

The Salesforce administrator needs the Data Cloud Architect permission set and V2 enabled for the org.

In Salesforce:

  1. Open Data Share Targets, create a target, and choose Snowflake V2.
  2. Enter its label and paste the Enrollment ID. Save it.
  3. Create or open a Data Share, selecting the Data 360 objects to expose and reviewing its consent/access settings.
  4. On that share, choose Link/Unlink Data Share Target, select the V2 target, and save.

The target identifies the receiving account. The share identifies the data. Creating a target alone does not publish any objects. Salesforce-side setup in Snowflake’s guide

Back in Snowflake, check the connection:

DESC ZEROCOPY CONNECTOR
  PLATFORM_ADMIN.ADMINISTRATION.SALESFORCE_ZC;
Enter fullscreen mode Exit fullscreen mode

Wait for CONNECTED before mounting.

Step 3: Mount the shares with legacy names available

I mounted all shares and enabled the legacy schema alias:

SELECT SYSTEM$ZEROCOPY_CONNECTOR_LIST_SHARES(
  'PLATFORM_ADMIN.ADMINISTRATION.SALESFORCE_ZC'
);

CREATE OR REPLACE DATABASE SALESFORCE_SHARED
  LINKED_ZEROCOPY_CONNECTOR = (
    CONNECTOR_NAME = 'PLATFORM_ADMIN.ADMINISTRATION.SALESFORCE_ZC',
    ALL_SHARES = TRUE,
    LEGACY_SALESFORCE_SCHEMA_ALIAS = TRUE
  );

SHOW SCHEMAS IN DATABASE SALESFORCE_SHARED;
Enter fullscreen mode Exit fullscreen mode

LEGACY_SALESFORCE_SCHEMA_ALIAS = TRUE keeps the schema_<share_name> alias available, helping existing queries survive the migration. For a generic share called CRM_DATA, this example uses "schema_CRM_DATA". Use the exact case returned in your environment:

SHOW VIEWS IN SCHEMA SALESFORCE_SHARED."schema_CRM_DATA";
Enter fullscreen mode Exit fullscreen mode

Use those views for queries. They can take about a minute to appear after mounting. Mounting and querying

The example reflects the CREATE OR REPLACE form I used. For a new database, plain CREATE DATABASE is sufficient; replacing an existing database is a separate operation, not a required connection step.

Step 4: Give the consuming role access

Mounting the database does not finish the consumer setup. I granted database and schema access, followed by access to both existing and future views:

GRANT USAGE ON DATABASE SALESFORCE_SHARED
  TO ROLE SALESFORCE_ANALYST;

GRANT USAGE ON SCHEMA SALESFORCE_SHARED."schema_CRM_DATA"
  TO ROLE SALESFORCE_ANALYST;

GRANT SELECT ON ALL VIEWS
  IN SCHEMA SALESFORCE_SHARED."schema_CRM_DATA"
  TO ROLE SALESFORCE_ANALYST;

GRANT SELECT ON FUTURE VIEWS
  IN SCHEMA SALESFORCE_SHARED."schema_CRM_DATA"
  TO ROLE SALESFORCE_ANALYST;
Enter fullscreen mode Exit fullscreen mode

ALL VIEWS covers existing views; FUTURE VIEWS covers subsequently created views in that schema. Repeat for other permitted schemas. These grants do not cover future schemas or warehouse access. Snowflake grant syntax

Cleaner names without breaking old references

Legacy experience V2 naming option
schema_brz_data schema alias Optional; I enabled it in this setup to retain the legacy name
Case_Home__dll object An additional friendly view named Case_Home
AccountId__c column AccountId in the friendly view

These are aliases, not a rename of Salesforce’s source objects. Friendly names default to enabled, so my SQL leaves SALESFORCE_USER_FRIENDLY_NAME unset. Both naming options are creation-time choices. Naming options

Where my incremental test stopped

Being able to query current data is different from knowing which records changed since the last run.

My stream test on an exposed view failed with this error (object identifiers omitted):

Change tracking is not supported on queries with
'Unmanaged Iceberg Table' inside views.
Enter fullscreen mode Exit fullscreen mode

My understanding is that this exposed-view path did not support the change tracking needed for the stream. Current-state queries worked; an insert/update/delete feed through that path did not.

That is narrower than saying “V2 does not support incremental processing.” Salesforce’s release notes explicitly describe using streams and tasks with V2. Snowflake’s general documentation also distinguishes stream support by table type and Iceberg version; streams on views require change tracking on the underlying tables. An insert-only stream is not a substitute for a complete update/delete feed. Salesforce’s stated capability, Snowflake stream support and limitations

The connector guides do not resolve this specific error. Before relying on downstream history, I would confirm the supported source object and stream configuration, then test one insert, one update, and one delete end to end.

Moving an existing connection

We captured grants before the change, applied the required grants to the new setup, and captured them again to compare. We did not assume that mounting the database would preserve access automatically.

That gives the migration two separate checks:

  • References: do the database, schema, and view names used by downstream queries still resolve?
  • Access: do the consuming roles retain the required privileges on the new objects?

Keep the legacy target linked while validating V2, and test representative queries under the consuming roles before unlinking it. Legacy schema aliases help preserve schema references, but do not replace the grants check. Snowflake documents the connection and database-switch procedure; existing connections are not upgraded automatically. Migration guide

For existing users: Salesforce’s current release notes specify October 31, 2026 for migrating legacy targets. Check that notice against your org’s rollout and migration plan. Migration notice

Have you used streams successfully with these Salesforce V2 objects? Which source object and stream configuration worked for you?

The GitHub examples include the V2 setup SQL, consumer grants, and a before-and-after migration checklist.

Top comments (0)