> For the complete documentation index, see [llms.txt](https://support.sayprimer.com/primer/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://support.sayprimer.com/primer/learn-more/upload-people-and-companies-to-primer-via-s3-beta/export-data-from-snowflake-to-primer-via-s3.md).

# Export Data from Snowflake to Primer via S3

Use Snowflake to export a complete people or company dataset as a CSV file to your Primer-provided Amazon S3 location.

Each export is a snapshot. Uploading the same filename replaces the corresponding dataset in Primer, including removing records that are no longer present in the file.

For details about the underlying Snowflake features, see:

* [Configure a Snowflake storage integration for Amazon S3](https://docs.snowflake.com/en/user-guide/data-load-s3-config-storage-integration)
* [CREATE STORAGE INTEGRATION](https://docs.snowflake.com/en/sql-reference/sql/create-storage-integration)
* [CREATE STAGE](https://docs.snowflake.com/en/sql-reference/sql/create-stage)
* [COPY INTO a location](https://docs.snowflake.com/en/sql-reference/sql/copy-into-location)
* [Data unloading considerations](https://docs.snowflake.com/en/user-guide/data-unload-considerations)
* [Introduction to Snowflake tasks](https://docs.snowflake.com/en/user-guide/tasks-intro)

### Before you begin

Ask your Primer representative for:

* The AWS role ARN Snowflake should assume
* The Snowflake-compatible S3 URL containing the access-point alias and your assigned prefix
* The S3 access-point ARN
* Your people and company folder paths

The locations will follow this pattern:

```
s3://<access-point-alias>/<prefix>/datasets/people/
s3://<access-point-alias>/<prefix>/datasets/companies/
```

In Snowflake, you need:

* A role with permission to create a storage integration
* Permission to create a stage in the selected database and schema
* A query that returns the complete dataset you want to send to Primer

Only `ACCOUNTADMIN` or a role granted the global `CREATE INTEGRATION` privilege can create a storage integration.

### 1. Create the storage integration

Create a storage integration using the role ARN and S3 location provided by Primer:

```
CREATE STORAGE INTEGRATION primer_s3_integration
  TYPE = EXTERNAL_STAGE
  STORAGE_PROVIDER = 'S3'
  ENABLED = TRUE
  STORAGE_AWS_ROLE_ARN = '<Primer-provided role ARN>'
  STORAGE_ALLOWED_LOCATIONS = (
    's3://<access-point-alias>/<prefix>/datasets/'
  );
```

Use the exact S3 URL provided by Primer. The allowed location must contain the people and company folders you intend to use.

Snowflake generates an external ID automatically when the integration is created. Avoid recreating the integration after Primer configures access: replacing it can generate a new external ID and invalidate the AWS trust relationship.

See [CREATE STORAGE INTEGRATION](https://docs.snowflake.com/en/sql-reference/sql/create-storage-integration) for the complete syntax and access-control requirements.

### 2. Send Snowflake’s identity to Primer

Retrieve the AWS identity generated for the integration:

```
DESC STORAGE INTEGRATION primer_s3_integration;
```

Send these two returned values to your Primer representative:

* `STORAGE_AWS_IAM_USER_ARN`
* `STORAGE_AWS_EXTERNAL_ID`

Primer must add this identity and external ID to the trust policy of your upload role. This authorizes Snowflake to assume the role and write to your assigned S3 location.

Wait for Primer to confirm that the trust relationship has been configured before creating and testing the stage.

For an explanation of this trust configuration, see [Configure a Snowflake storage integration for Amazon S3](https://docs.snowflake.com/en/user-guide/data-load-s3-config-storage-integration).

### 3. Create an external stage

Create a stage for the type of data you want to export.

For people:

```
CREATE STAGE primer_people_stage
  URL = 's3://<access-point-alias>/<prefix>/datasets/people/'
  AWS_ACCESS_POINT_ARN = '<Primer-provided access-point ARN>'
  STORAGE_INTEGRATION = primer_s3_integration
  FILE_FORMAT = (
    TYPE = CSV
    COMPRESSION = NONE
    FIELD_OPTIONALLY_ENCLOSED_BY = '"'
  );
```

For companies:

```
CREATE STAGE primer_companies_stage
  URL = 's3://<access-point-alias>/<prefix>/datasets/companies/'
  AWS_ACCESS_POINT_ARN = '<Primer-provided access-point ARN>'
  STORAGE_INTEGRATION = primer_s3_integration
  FILE_FORMAT = (
    TYPE = CSV
    COMPRESSION = NONE
    FIELD_OPTIONALLY_ENCLOSED_BY = '"'
  );
```

Snowflake requires `AWS_ACCESS_POINT_ARN` when the stage URL uses an S3 access-point alias. Multi-region S3 access points are not supported.

The role creating the stage must have `CREATE STAGE` on the schema and `USAGE` on the storage integration. See [CREATE STAGE](https://docs.snowflake.com/en/sql-reference/sql/create-stage) for details.

### 4. Prepare the export query

Map your Snowflake columns to Primer’s supported CSV headers.

Example people query:

```
SELECT
  first_name     AS "First Name",
  last_name      AS "Last Name",
  email          AS "Email",
  linkedin_url   AS "Person Linkedin Url",
  company_name   AS "Company Name",
  company_domain AS "Company Domain",
  country        AS "Country",
  state          AS "State",
  city           AS "City"
FROM analytics.contacts;
```

Example company query:

```
SELECT
  company_name   AS "Company Name",
  company_domain AS "Company Domain",
  linkedin_url   AS "LinkedIn URL",
  country        AS "Country",
  state          AS "State",
  city           AS "City"
FROM analytics.companies;
```

The query must return the complete snapshot you want Primer to retain. Before exporting, review the query results and confirm that the row count is reasonable.

### 5. Export a test file

Export the people query as a single, uncompressed CSV file:

```
COPY INTO @primer_people_stage/contacts.csv
FROM (
  SELECT
    first_name     AS "First Name",
    last_name      AS "Last Name",
    email          AS "Email",
    linkedin_url   AS "Person Linkedin Url",
    company_name   AS "Company Name",
    company_domain AS "Company Domain",
    country        AS "Country",
    state          AS "State",
    city           AS "City"
  FROM analytics.contacts
)
HEADER = TRUE
SINGLE = TRUE
OVERWRITE = TRUE;
```

For a company export, use the company stage and query:

```
COPY INTO @primer_companies_stage/accounts.csv
FROM (
  SELECT
    company_name   AS "Company Name",
    company_domain AS "Company Domain",
    linkedin_url   AS "LinkedIn URL",
    country        AS "Country",
    state          AS "State",
    city           AS "City"
  FROM analytics.companies
)
HEADER = TRUE
SINGLE = TRUE
OVERWRITE = TRUE;
```

These settings are required:

* `HEADER = TRUE` includes Primer’s column names.
* `SINGLE = TRUE` produces one CSV file instead of multiple output files.
* `OVERWRITE = TRUE` replaces the existing object with the same name.
* `COMPRESSION = NONE`, configured on the stage, produces an uncompressed CSV.

Snowflake normally unloads data into multiple files. `SINGLE = TRUE` is necessary because Primer treats each filename as a separate dataset. See [COPY INTO a location](https://docs.snowflake.com/en/sql-reference/sql/copy-into-location) and [Data unloading considerations](https://docs.snowflake.com/en/user-guide/data-unload-considerations).

### 6. Verify the import in Primer

After the export completes:

1. Wait 15–60 minutes.
2. Open the [CSV Imports page in Primer](https://my.sayprimer.com/connections?tab=CSV%20Imports).
3. Find the dataset associated with `contacts.csv` or `accounts.csv`.
4. Confirm that the expected records and fields appear.
5. Change or remove a test record in the source query results.
6. Run the same `COPY INTO` statement again.
7. Confirm that Primer updated the dataset and removed any record omitted from the new snapshot.

Do not change the filename between runs. A different filename creates a separate dataset in Primer.

### 7. Schedule the export

After validating the replacement behavior, run the same `COPY INTO` statement from your existing orchestration system or schedule it with a Snowflake task.

A Snowflake task is optional. If you already use an orchestrator such as Airflow, dbt Cloud, or another scheduler, you can run the validated `COPY INTO` statement there.

Example serverless Snowflake task:

```
CREATE TASK primer_people_export
  SCHEDULE = 'USING CRON 0 6 * * * UTC'
AS
COPY INTO @primer_people_stage/contacts.csv
FROM (
  SELECT
    first_name     AS "First Name",
    last_name      AS "Last Name",
    email          AS "Email",
    linkedin_url   AS "Person Linkedin Url",
    company_name   AS "Company Name",
    company_domain AS "Company Domain",
    country        AS "Country",
    state          AS "State",
    city           AS "City"
  FROM analytics.contacts
)
HEADER = TRUE
SINGLE = TRUE
OVERWRITE = TRUE;
```

New Snowflake tasks are created in a suspended state. Enable the schedule after testing the export:

```
ALTER TASK primer_people_export RESUME;
```

Snowflake does not run overlapping instances of the same scheduled task. If one run is still active at the next scheduled time, Snowflake skips that scheduled run.

See [Introduction to Snowflake tasks](https://docs.snowflake.com/en/user-guide/tasks-intro) for task permissions, scheduling options, and operational behavior.

### Operational requirements

For every recurring export:

* Export a complete snapshot, not only changed records.
* Use the same filename on every run.
* Write people and company files to their corresponding folders.
* Include a CSV header row.
* Produce one uncompressed CSV file.
* Review unexpected row-count changes before exporting.
* Do not run separate export jobs against the same filename concurrently.
* Keep the storage integration in place while the scheduled export is active.

If you need to change the filename, folder, access point, or storage integration, contact Primer before the next export.


---

# 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://support.sayprimer.com/primer/learn-more/upload-people-and-companies-to-primer-via-s3-beta/export-data-from-snowflake-to-primer-via-s3.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.
