Skip to main content
This guide describes how to prepare a Snowflake Open Catalog (Polaris) for use with StreamNative Ursa as an Iceberg catalog on Google Cloud Platform (GCP).
Important: Polaris does not support reading buckets from a different region. The StreamNative Ursa cluster, the GCS bucket, and the Polaris catalog must all reside in the same region.

Prerequisites

  • A Snowflake standard account
  • A GCP project with permissions to create GCS buckets and IAM roles
  • Access to the Snowflake Open Catalog feature

1. Create a Snowflake Open Catalog Account

The Snowflake Open Catalog console requires a dedicated Open Catalog account. From the standard Snowflake console, navigate to Admin -> Accounts and use the toggle to Create Snowflake Open Catalog Account. Snowflake console Create Open Catalog account Configure the account with:
  • Cloud: GCP
  • Region: the region in which your GCS bucket resides
  • Edition: any
Account configuration Provide an admin username and password. Account credentials After creation, click the Account URL to sign in to the Open Catalog console. Account created Open Catalog console

2. Create the Polaris Catalog

In the Snowflake Open Catalog console, create a new catalog. Create catalog Configure the catalog with:
  • External: disabled
  • Storage provider: GCS
  • Default base location: the GCS path used by the Ursa cluster (gs://<bucket>/<subpath>)
Catalog configuration Catalog created Open the catalog details and record the GCP_SERVICE_ACCOUNT value. Polaris uses this service account to access GCS, so it must be granted permission on the bucket. Catalog GCP service account

3. Grant Bucket Permissions to the Polaris Service Account

3.1 Create a Custom IAM Role

In the GCP console, navigate to IAM & Admin -> Roles -> Create role and add the following permissions:
  • storage.buckets.get
  • storage.objects.create
  • storage.objects.delete
  • storage.objects.get
  • storage.objects.list
Create role Role setup Permissions Permissions selected

3.2 Assign the Role to the Polaris Service Account

Open the bucket, navigate to PERMISSIONS -> View BY PRINCIPALS -> GRANT ACCESS. Grant bucket access Add the GCP_SERVICE_ACCOUNT from step 3, choose the role created in step 4.1, and click SAVE. Save access

4. Create a Connection (Service Principal)

In the Open Catalog console, create a new connection that StreamNative Ursa will use to authenticate. Create connection Configure with:
  • Name: any name
  • Create new principal role: enabled
  • Principal Role Name: any name
Connection configuration After creation, record the Client ID and Client Secret — the secret cannot be retrieved later. Connection credentials

5. Create a Catalog Role and Grant Privileges

Navigate to Catalogs -> [your catalog] -> Roles -> + Catalog Role and create a role with the following privileges:
  • NAMESPACE_CREATE
  • NAMESPACE_LIST
  • NAMESPACE_READ_PROPERTIES
  • NAMESPACE_WRITE_PROPERTIES
  • TABLE_LIST
  • TABLE_CREATE
  • TABLE_WRITE_DATA
  • TABLE_READ_DATA
  • TABLE_READ_PROPERTIES
  • TABLE_WRITE_PROPERTIES
Create catalog role Click Grant to Principals Role and grant the catalog role to the principal role created in step 5. Grant to principal role Grant configuration Role bindings For background on the relationship between catalogs, catalog roles, principal roles, and principals, see the Polaris Quick Start.

Catalog Information Summary

When the steps above are complete, collect the following values for the StreamNative Ursa compaction service:
ValueDescription
iceberg.uriPolaris REST endpoint (e.g., https://<account>.<region>.gcp.snowflakecomputing.com/polaris/api/catalog). The format follows the URL of your Polaris console.
iceberg.warehouseThe Polaris catalog name created in step 3
iceberg.credential<client-id>:<client-secret> from step 5
iceberg.scopePRINCIPAL_ROLE:ALL

Table Maintenance

Snowflake Open Catalog (Polaris) and the Hadoop catalog do not run table maintenance on your behalf. Streaming writes from the StreamNative Ursa compaction service produce many small Parquet files and accumulate snapshot history over time, which degrades query performance and inflates storage costs. You are responsible for scheduling and running maintenance against every Iceberg table written by Ursa. Run the maintenance operations below on a regular schedule. They are provided as Apache Iceberg Spark stored procedures and can be triggered from any Spark cluster (Databricks, AWS EMR, AWS Glue, GCP Dataproc, or self-managed Spark) that has the Iceberg Spark runtime, catalog credentials, and IAM access to the warehouse bucket. Maintenance operations
OperationPurposeSuggested cadence
rewrite_data_filesCompact small Parquet files into fewer, larger files. Reduces file-listing overhead and improves scan performance.Hourly to daily, depending on ingestion rate
expire_snapshotsDrop snapshots older than the retention window so their data and manifest files can be cleaned up.Daily; retain at least 1–7 days so in-flight readers and time-travel queries keep working
remove_orphan_filesDelete files in the table location that are no longer referenced by any snapshot (typically left behind by failed or partial writes).Weekly
rewrite_manifestsRewrite manifest files so they align with the current partition layout. Improves query planning time.Weekly, or after large schema or partition changes
Example: run maintenance from Spark The following examples assume the catalog has been registered in Spark as <catalog>. Replace <catalog>, <namespace>, and <table> with your values.
-- Compact small files. Iceberg targets files smaller than the default 512 MB.
CALL <catalog>.system.rewrite_data_files(table => '<namespace>.<table>');

-- Expire snapshots older than 3 days; keep the 5 most recent snapshots.
CALL <catalog>.system.expire_snapshots(
  table       => '<namespace>.<table>',
  older_than  => TIMESTAMP '2026-05-20 00:00:00',
  retain_last => 5
);

-- Remove orphan files older than 7 days.
CALL <catalog>.system.remove_orphan_files(
  table      => '<namespace>.<table>',
  older_than => TIMESTAMP '2026-05-20 00:00:00'
);

-- Rewrite manifests to match the current partition layout.
CALL <catalog>.system.rewrite_manifests(table => '<namespace>.<table>');
Operational guidance
  • Credentials. The principal that runs maintenance must have catalog privileges to read and write the target table (for example, the same TABLE_READ_DATA, TABLE_WRITE_DATA, TABLE_READ_PROPERTIES, and TABLE_WRITE_PROPERTIES privileges configured for the Ursa compaction service) and IAM access to the warehouse bucket so it can read and rewrite the underlying data files. With the Hadoop catalog there is no catalog service to authenticate against — only the bucket IAM access is required.
  • Concurrency. Iceberg uses optimistic concurrency control. If maintenance commits race with the Ursa compaction writer, one of them retries. Schedule heavy operations (rewrite_data_files, rewrite_manifests) during low-write windows when possible.
  • Retention vs. time travel. expire_snapshots and remove_orphan_files permanently delete files. Choose a retention window that exceeds the longest expected read query and your time-travel SLA.
  • Schedule the workload. Most teams orchestrate these procedures from Databricks Jobs, AWS EMR steps, Airflow, Dagster, or a Kubernetes CronJob. Pick a scheduler that fits your existing operational stack.
  • Reference. See the Iceberg Spark procedures documentation for the full parameter list, including options for partial rewrites (where), file-size targets, and merge-on-read delete file compaction.
For the next steps, see Configure Lakehouse Catalogs.