Overview
The Snowflake Sink Connector continuously writes records from Kafka topics to Snowflake tables. It sits in the data-writing path between Kafka and Snowflake. It uses Snowpipe Streaming to write data from each topic partition to the corresponding Snowflake ingestion channel. It can determine target tables from topic names or route topics to specified tables through mappings. The Connector can expand structured records into Snowflake columns or write records to theRECORD_CONTENT and RECORD_METADATA columns. It is suitable for continuously writing business events, logs, and change data.
Prerequisites
- The target Snowflake database, schema, user, and role must exist and have permission to access the target objects, create or write tables, and use Snowpipe Streaming.
- JWT authentication requires an RSA private key. OAuth authentication requires a client ID, client secret, and the tokens or endpoints required by the selected flow.
- When using an existing table, its structure must be compatible with the record conversion and metadata settings. Managed Iceberg tables also require external volume and catalog configuration.
License
Uses Apache License 2.0.Quick Start
Prepare a Connect Cluster, Kafka topic, and target Snowflake database and schema in advance. Confirm that the Connect Worker can access Kafka and Snowflake and has the required permissions. For creating and managing the Connector, see AutoMQ’s Manage Connectors.orders topic, automatically creates the missing Snowflake table in the target schema, and writes records to the RECORD_CONTENT and RECORD_METADATA columns.
Configuration
Connection and Authentication
snowflake.url.name
Snowflake account URL. This property has no usable runtime default.
- Type:
STRING - Default: None
- Importance: High
- Required: Yes
snowflake.user.name
User for JWT or OAuth Snowflake sessions.
- Type:
STRING - Default: None
- Importance: High
- Required: Yes
snowflake.private.key
Required by the default snowflake_jwt authenticator. A Kafka Config Provider reference can be used.
- Type:
PASSWORD - Default: empty string
- Importance: High
- Required: Conditionally required
snowflake.private.key.passphrase
Set only for an encrypted RSA private key. A Config Provider reference can be used.
- Type:
PASSWORD - Default: empty string
- Importance: Low
- Required: No
snowflake.database.name
The target Snowflake database must exist and be accessible to the configured role.
- Type:
STRING - Default: None
- Importance: High
- Required: Yes
snowflake.schema.name
The target schema must exist and be accessible to the configured role.
- Type:
STRING - Default: None
- Importance: High
- Required: Yes
snowflake.role.name
Specifies the Snowflake session role. When OAuth scope inclusion is enabled without an explicit scope, it is also used to derive session:role:<role>.
- Type:
STRING - Default: None
- Importance: High
- Required: Yes
snowflake.authenticator
Selects JWT or OAuth authentication, which have mutually exclusive credential requirements. Valid values are snowflake_jwt and oauth.
- Type:
STRING - Default: snowflake_jwt
- Importance: Low
- Required: No
snowflake.oauth.client.id
Required for OAuth. A Config Provider reference defers live credential validation.
- Type:
STRING - Default: empty string
- Importance: High
- Required: Conditionally required
snowflake.oauth.client.secret
Required for OAuth. A Config Provider reference defers live credential validation.
- Type:
PASSWORD - Default: empty string
- Importance: High
- Required: Conditionally required
snowflake.oauth.refresh.token
An empty value selects the OAuth client_credentials flow; a nonempty value selects the refresh-token flow.
- Type:
PASSWORD - Default: empty string
- Importance: High
- Required: No
snowflake.oauth.token.endpoint
When unset, the token endpoint is derived from the Snowflake account URL.
- Type:
STRING - Default: None
- Importance: High
- Required: No
snowflake.oauth.include.scope
false sends no scope. true sends the explicit scope, or session:role:<role> when no scope is set.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
snowflake.oauth.scope
Used only when snowflake.oauth.include.scope=true. An empty value then derives the scope from the configured role.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
Network Proxy
jvm.proxy.host
A nonempty value sets process-wide HTTP and HTTPS JVM proxy properties. It must be configured together with jvm.proxy.port.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: Conditionally required
jvm.proxy.port
Passed as the JVM proxy port string. It must be configured together with jvm.proxy.host.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: Conditionally required
jvm.nonProxy.hosts
When the proxy host and port are active, this value is appended to the existing http.nonProxyHosts JVM property with |.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
jvm.proxy.username
Used only when the proxy host and port are active. It must be configured together with jvm.proxy.password.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: Conditionally required
jvm.proxy.password
Used only when the proxy host and port are active. It must be configured together with jvm.proxy.username.
- Type:
PASSWORD - Default: empty string
- Importance: Low
- Required: Conditionally required
Tables and Data Model
snowflake.metadata.all
Master metadata switch. false discards record metadata regardless of the individual field switches. It must remain true for managed Iceberg tables.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.metadata.createtime
Controls creation-time metadata. It must remain true for managed Iceberg tables.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.metadata.topic
Controls topic metadata. It must remain true for managed Iceberg tables.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.metadata.offset.and.partition
Controls both Kafka offset and partition metadata. It must remain true for managed Iceberg tables.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.streaming.metadata.connectorPushTime
Controls Connector push-time metadata. It must remain true for managed Iceberg tables.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.feature.structured.headers
true preserves converted structured header types; false flattens header values to strings. Enabling it can break consumers that depend on the legacy metadata representation.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
Compatibility and Migration
snowflake.streaming.validate.compatibility.with.classic
The default true is a v3 migration safety gate. While enabled, set snowflake.validation=client_side, set both snowflake.compatibility.* normalization switches to true, and explicitly set snowflake.enable.schematization and snowflake.streaming.classic.offset.migration. When migration mode is strict or best_effort, also explicitly set snowflake.streaming.classic.offset.migration.include.connector.name. For a new v4 Connector that does not require v3 compatibility, explicitly set this property to false.
- Type:
BOOLEAN - Default: true
- Importance: High
- Required: No
Topic Routing, Validation, and Migration
snowflake.topic2table.map
Comma-separated topic:table mappings. Quoted table names preserve case, while unquoted names are uppercased. An empty value derives table names from topic names.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
snowflake.validation
Valid values are server_side and client_side. server_side requires error logging on the target table. Managed Iceberg tables do not support client_side.
- Type:
STRING - Default: server_side
- Importance: High
- Required: No
snowflake.streaming.classic.offset.migration
Valid values are skip, best_effort, and strict. A v3 Classic channel is consulted only when the SSv2 channel has no committed offset. strict fails when the legacy channel is absent, best_effort falls back to the Kafka consumer-group offset, and skip does not consult legacy channels.
- Type:
STRING - Default: skip
- Importance: High
- Required: Conditionally required
snowflake.streaming.classic.offset.migration.include.connector.name
Used only with strict or best_effort. The value must match whether the v3 Connector included the Connector name in channel names.
- Type:
BOOLEAN - Default: false
- Importance: High
- Required: Conditionally required
behavior.on.null.values
Valid values are default and ignore. ignore filters Kafka tombstones. default retains the legacy behavior and writes empty JSON content to the target table.
- Type:
STRING - Default: default
- Importance: Low
- Required: No
Logging, Metrics, and Advanced Options
jmx
Enables the Connector’s custom Snowflake metrics MBeans.
- Type:
BOOLEAN - Default: true
- Importance: High
- Required: No
snowflake.streaming.client.provider.override.map
Advanced Snowpipe Streaming SDK overrides. Use only under guidance from Snowflake Support.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
Error Handling
errors.tolerance
Valid values are all and none. all tolerates Connector-side ingestion or validation record failures and can preserve them in a DLQ. none fails the Task.
- Type:
STRING - Default: none
- Importance: Low
- Required: No
errors.log.enable
Logs tolerated record failures. Consider record sensitivity before enabling detailed framework message logging.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
errors.deadletterqueue.topic.name
Preserves tolerated failures when errors.tolerance=all. An empty value disables DLQ output.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
enable.mdc.logging
Enables global MDC context for Connector logs.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
enable.task.fail.on.authorization.errors
When true, a previously observed Snowflake authorization error causes the Task to fail during preCommit.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
snowflake.compatibility.enable.autogenerated.table.name.sanitization
true sanitizes and uppercases automatically generated table names for v3 compatibility. false passes topic names through. Use an explicit snowflake.topic2table.map for special names.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: Conditionally required
snowflake.compatibility.enable.column.identifier.normalization
true normalizes column identifiers to uppercase for v3 compatibility.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: Conditionally required
snowflake.enable.schematization
true maps records to individual columns. false writes the v3-compatible RECORD_CONTENT and RECORD_METADATA VARIANT columns.
- Type:
BOOLEAN - Default: true
- Importance: Medium
- Required: Conditionally required
snowflake.autocreate.table.type
Valid values are snowflake, iceberg, and none. The first two automatically create a missing table of that type; none fails when the table is missing. Existing tables are always used with their current type and schema.
- Type:
STRING - Default: snowflake
- Importance: Medium
- Required: No
snowflake.iceberg.create.table.options
SQL clauses appended to the CREATE statement for an automatically created managed Iceberg table. Do not include CATALOG, ENABLE_SCHEMA_EVOLUTION, or ERROR_LOGGING. Existing tables ignore this property.
- Type:
STRING - Default: empty string
- Importance: Low
- Required: No
snowflake.cache.table.exists
Enables caching of target-table existence checks.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.cache.table.exists.expire.ms
Table-existence cache expiration in milliseconds. The minimum value is 1.
- Type:
LONG - Default: 300000
- Importance: Low
- Required: No
snowflake.cache.pipe.exists
Enables caching of Pipe existence checks.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
snowflake.cache.pipe.exists.expire.ms
Pipe-existence cache expiration in milliseconds. The minimum value is 1.
- Type:
LONG - Default: 300000
- Importance: Low
- Required: No
snowflake.topic2table.map.regex.replacement
true enables Java regex capture-group replacement in mapped table-name templates. false preserves literal $ characters and the legacy no-substitution behavior.
- Type:
BOOLEAN - Default: false
- Importance: Low
- Required: No
Concurrency and Conversion
connector.class
Use com.snowflake.kafka.connector.SnowflakeStreamingSinkConnector. This is a Kafka Connect framework property, not part of the Connector’s own ConfigDef.
- Type:
STRING - Default: No fixed default
- Importance: High
- Required: Yes
tasks.max
Upper bound on the requested Task count. Effective parallelism is also bounded by the assigned topic partitions.
- Type:
INT - Default: 1
- Importance: High
- Required: No
tasks.max.enforce
When true, Kafka Connect fails a Connector task set that exceeds tasks.max.
- Type:
BOOLEAN - Default: true
- Importance: Low
- Required: No
- Deprecated: Yes
- Replacement: None
topics
Comma-separated topic list. Exactly one of topics and topics.regex must be configured.
- Type:
LIST - Default: empty string
- Importance: High
- Required: Conditionally required
topics.regex
Full Java regular expression for topic subscription. Exactly one of topics and topics.regex must be configured.
- Type:
STRING - Default: empty string
- Importance: High
- Required: Conditionally required
key.converter
When unset, inherits the Worker key converter. Converter-specific subproperties depend on the selected plugin and have no universal default.
- Type:
CLASS - Default:
null(inherits the Worker configuration) - Importance: Low
- Required: No
value.converter
When unset, inherits the Worker value converter. Converter-specific properties such as schemas.enable depend on the selected Converter and have no universal default.
- Type:
CLASS - Default:
null(inherits the Worker configuration) - Importance: Low
- Required: No
errors.deadletterqueue.topic.replication.factor
Used only when Kafka Connect creates a missing DLQ topic. The value must be valid for the number of brokers in the target Kafka cluster.
- Type:
SHORT - Default: 3
- Importance: Medium
- Required: No
errors.deadletterqueue.context.headers.enable
Adds __connect.errors.* context headers to DLQ records written by the framework.
- Type:
BOOLEAN - Default: false
- Importance: Medium
- Required: No
Best Practices
Route Multiple Topics to Explicit Target Tables
Applicable business scenario: One Connector must write different topics to different Snowflake tables, or a topic name cannot be used directly as a target table name. Configuration example: Add explicit mappings to the base configuration.Tolerate Record Errors and Retain Failed Records
Applicable business scenario: Individual records may fail in the Converter or Connector-side processing, but the continuous write task must keep running while failed records are retained for troubleshooting. Configuration example: Enable Connect error tolerance and a DLQ, and ensure that the DLQ topic is not matched by the current subscription.3; if the cluster has fewer brokers, pre-create the topic or explicitly adjust errors.deadletterqueue.topic.replication.factor.
Monitoring
What to Monitor
Monitor Kafka Connect Worker health, Connector and Task status, throughput, latency, offset commits, errors and retries, as well as Worker JVM heap, GC, threads, and CPU. After enabling error tolerance and a DLQ, also monitor DLQ write volume, failed-record growth, and delivery errors.Import the Grafana Dashboard
Download the AutoMQ Connect Cluster Dashboard. In Grafana, select the data source that collects Kafka Connect metrics, confirm that the metric labels match the dashboard variables, and import the JSON file.Limitations
- No global record ordering is provided across Tasks, topics, or Kafka partitions.
- The committed Snowflake channel offset plus one is the recovery and Kafka commit boundary for an individual topic partition. If the committed channel status cannot be read, that partition is not reported as safe to commit.
- Replayed records at offsets already known to be committed are skipped, but this mechanism is not an atomic exactly-once guarantee across Tasks, partitions, or tables.
- When
snowflake.autocreate.table.type=none, a missing target table causes task initialization to fail. - Managed Iceberg tables are incompatible with
snowflake.validation=client_side. - Offset commits and recovery are bounded by topic partitions; atomic checkpoints across multiple partitions or tables are not provided.
- Backend throttling, channel recovery failures, and unrecoverable ingestion errors can cause the task to fail.
FAQ
What should I do when the task reports missing required configuration at startup?
Check the Snowflake URL, user, database, schema, and role. The default authenticator issnowflake_jwt, which also requires snowflake.private.key. When using OAuth, instead check the OAuth client ID and secret.
Why are records not written to the target table after a topic is configured?
Confirm that only one oftopics and topics.regex is configured, and check whether the subscription matches the actual topic. Then check database, schema, and role permissions, as well as explicit mappings and automatic table-creation settings.
Why does a Classic compatibility configuration error appear at startup?
The default compatibility validation requiressnowflake.validation=client_side, both v3 normalization switches set to true, and explicit schematization and Classic offset-migration settings. For a new 4.1.0 Connector that does not require v3 compatibility, set snowflake.streaming.validate.compatibility.with.classic=false. When migrating from v3, select strict or best_effort and set snowflake.streaming.classic.offset.migration.include.connector.name according to whether the previous Connector enabled snowflake.streaming.channel.name.include.connector.name.
Why cannot structured data be converted?
When schematization is enabled, the value must be convertible to a Map or Struct, and StringConverter or ByteArrayConverter cannot be used. Check the Converter, message structure, and target table permissions.Why do failed records not appear in the DLQ?
Confirm thaterrors.tolerance=all is set, the DLQ topic is configured and is not matched by the current subscription, and the Worker provides ErrantRecordReporter and Kafka allows writes to that topic.