Skip to main content

K2I Configuration Reference

K2I uses TOML configuration files. This document describes all available configuration options.

Use this page as the source of truth for runtime configuration. For feature-specific behavior, see Schema Registry Protobuf, Iceberg REST Catalog, and Production Readiness.

Configuration File Location​

By default, K2I looks for config.toml in the current directory. Override with:

k2i ingest --config /path/to/config.toml

Complete Configuration Example​

[kafka]
bootstrap_servers = ["localhost:9092"]
topic = "events"
consumer_group = "k2i-ingestion"
batch_size = 1000
batch_timeout_ms = 5000
session_timeout_ms = 30000
heartbeat_interval_ms = 3000
max_poll_interval_ms = 300000
auto_offset_reset = "earliest"

[kafka.format]
type = "raw"

# Protobuf example:
# [kafka.format]
# type = "protobuf"
# schema_registry_url = "http://localhost:8081"
# subject_strategy = "topic_name"
# message_type = "example.events.v1.Event"
# cache_ttl_seconds = 300
# latest_on_startup = true

[kafka.security]
protocol = "SASL_SSL"
sasl_mechanism = "SCRAM-SHA-256"
sasl_username = "user"
sasl_password = "password"
ssl_ca_location = "/path/to/ca.pem"
ssl_cert_location = "/path/to/cert.pem"
ssl_key_location = "/path/to/key.pem"

[schema_evolution]
mode = "auto-additive"
on_breaking_change = "pause"
schema_update_min_interval_seconds = 60

[iceberg]
catalog_type = "rest"
warehouse_path = "s3://bucket/warehouse"
database_name = "raw"
table_name = "events"
target_file_size_mb = 512
compression = "snappy"
rest_uri = "http://localhost:8181"
aws_region = "us-east-1"
aws_access_key_id = "AKIAIOSFODNN7EXAMPLE"
aws_secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
s3_endpoint = "http://localhost:9000"

[[iceberg.partition_spec]]
source_field = "event_timestamp"
transform = "day"

[buffer]
ttl_seconds = 60
max_size_mb = 500
flush_interval_seconds = 30
flush_batch_size = 10000
memory_alignment_bytes = 64

[transaction_log]
log_dir = "./transaction_logs"
checkpoint_interval_entries = 10000
checkpoint_interval_seconds = 300
max_log_files = 10

[maintenance]
compaction_enabled = true
compaction_interval_seconds = 3600
compaction_threshold_mb = 100
compaction_target_mb = 512
snapshot_expiration_enabled = true
snapshot_retention_days = 7
orphan_cleanup_enabled = true
orphan_retention_days = 3

[monitoring]
metrics_port = 9090
health_port = 8080
log_level = "info"
log_format = "json"

[rpc]
enabled = false
socket_path = "./run/k2i.sock"
read_timeout_ms = 1000
max_concurrent_scans = 64
scan_ttl_seconds = 300
max_frame_bytes = 67108864

Kafka Configuration​

[kafka]​

OptionTypeRequiredDefaultDescription
bootstrap_serversArray[String]Yes-Kafka broker addresses
topicStringYes-Kafka topic to consume
consumer_groupStringYes-Consumer group ID
batch_sizeIntegerNo1000Messages per poll batch
batch_timeout_msIntegerNo5000Poll timeout in milliseconds
session_timeout_msIntegerNo30000Consumer session timeout
heartbeat_interval_msIntegerNo3000Heartbeat interval
max_poll_interval_msIntegerNo300000Max time between polls (5 min)
auto_offset_resetStringNo"earliest"Offset reset policy: earliest or latest

Notes​

  • max_poll_interval_ms must exceed the longest possible flush time to avoid consumer group rebalances
  • session_timeout_ms should be at least 3x heartbeat_interval_ms
  • Use earliest to process all historical data, latest for new messages only

[kafka.format]​

Controls how Kafka values are decoded before they enter the hot buffer and Parquet writer.

OptionTypeRequiredDefaultDescription
typeStringNo"raw"Payload format: raw, json, or protobuf
schema_registry_urlStringProtobuf only-Confluent Schema Registry base URL
subject_strategyStringNo"topic_name"Protobuf subject strategy: topic_name, record_name, topic_record_name
message_typeStringConditional-Fully-qualified Protobuf message type
cache_ttl_secondsIntegerNo300In-memory Schema Registry cache TTL
latest_on_startupBooleanNotrueResolve the latest subject schema during startup

raw stores Kafka key/value bytes with Kafka metadata columns. json currently uses the same raw decoder in the ingestion loop. protobuf expects Confluent-framed Protobuf values with the magic byte, schema ID, message indexes, and payload.

For record_name and topic_record_name, message_type is required. It is also required when a Protobuf schema contains more than one non-map-entry message type. K2I stores a stale Schema Registry disk cache under <transaction_log.log_dir>/schema-cache so recent schemas can still be resolved during short registry outages.

Example:

[kafka.format]
type = "protobuf"
schema_registry_url = "http://schema-registry:8081"
subject_strategy = "topic_name"
message_type = "example.events.v1.Event"
cache_ttl_seconds = 300
latest_on_startup = true

[kafka.security]​

Optional section for authenticated Kafka clusters.

OptionTypeRequiredDefaultDescription
protocolStringNo"PLAINTEXT"Security protocol
sasl_mechanismStringConditional-SASL mechanism (required if protocol uses SASL)
sasl_usernameStringConditional-SASL username
sasl_passwordStringConditional-SASL password
ssl_ca_locationStringNo-Path to CA certificate
ssl_cert_locationStringNo-Path to client certificate
ssl_key_locationStringNo-Path to client private key

Security Protocols​

ProtocolDescription
PLAINTEXTNo encryption or authentication
SSLTLS encryption, no SASL
SASL_PLAINTEXTSASL authentication, no encryption
SASL_SSLSASL authentication with TLS encryption

SASL Mechanisms​

MechanismDescription
PLAINSimple username/password
SCRAM-SHA-256Salted challenge-response (recommended)
SCRAM-SHA-512Stronger variant of SCRAM

Schema Evolution Configuration​

[schema_evolution]​

Controls runtime behavior when decoded Protobuf schemas differ from the current table schema.

OptionTypeRequiredDefaultDescription
modeStringNo"auto-additive"Evolution policy: manual, auto-additive, or permissive
on_breaking_changeStringNo"pause"Breaking-change policy: pause, fail, or skip-message
schema_update_min_interval_secondsIntegerNo60Minimum interval between schema update commits

In auto-additive mode, K2I automatically adds nullable fields that appear in new Protobuf schemas. Type changes, removed fields, required-field additions, and incompatible field changes are breaking. Breaking changes block /readyz; pause keeps the process alive for operator intervention, while fail marks schema health unhealthy. skip-message currently pauses instead of skipping so Kafka offsets are not advanced past incompatible data.

Use manual when an operator or deployment pipeline owns table schema changes. In manual mode, additive changes also pause ingestion until the table schema is updated.


Iceberg Configuration​

[iceberg]​

OptionTypeRequiredDefaultDescription
catalog_typeStringYes-Catalog type: rest, hive, glue, nessie
warehouse_pathStringYes-Base path for Iceberg tables
database_nameStringYes-Database/namespace name
table_nameStringYes-Table name
target_file_size_mbIntegerNo512Target Parquet file size
compressionStringNo"snappy"Compression: snappy, zstd, lz4, gzip, none

Catalog-Specific Options​

REST Catalog:

OptionTypeRequiredDescription
rest_uriStringYesREST catalog endpoint URL

Hive Metastore:

OptionTypeRequiredDescription
hive_metastore_uriStringYesThrift metastore URI

AWS Glue:

OptionTypeRequiredDescription
aws_regionStringYesAWS region
aws_access_key_idStringNoAWS access key (or use IAM role)
aws_secret_access_keyStringNoAWS secret key

Nessie:

OptionTypeRequiredDescription
rest_uriStringYesNessie server endpoint

Object Storage Options​

OptionTypeRequiredDefaultDescription
aws_regionStringNo-AWS region for S3
aws_access_key_idStringNo-AWS access key ID
aws_secret_access_keyStringNo-AWS secret access key
s3_endpointStringNo-Custom S3 endpoint (for MinIO, LocalStack)

Warehouse Path Formats​

StorageFormatCurrent writer status
AWS S3 / S3-compatibles3://bucket-name/path/Supported path; validate credentials and endpoint in your environment
Local filesystemfile:///absolute/path/Supported for local development and tests
Google Cloud Storagegs://bucket-name/path/Declared in configuration, but writer creation still needs backend wiring
Azure Blob Storageaz://container/path/Declared in configuration, but writer creation still needs backend wiring

[[iceberg.partition_spec]]​

Optional array of partition specifications. Multiple specs can be defined.

OptionTypeRequiredDescription
source_fieldStringYesSource column name
transformStringYesPartition transform

Partition Transforms​

TransformDescriptionExample
identityUse value as-iscountry
yearExtract year from timestampyear(event_time)
monthExtract year-monthmonth(event_time)
dayExtract year-month-dayday(event_time)
hourExtract year-month-day-hourhour(event_time)
bucket[N]Hash into N bucketsbucket[16](user_id)
truncate[N]Truncate string to N charstruncate[2](country_code)

Example Partition Specs​

# Partition by day
[[iceberg.partition_spec]]
source_field = "event_timestamp"
transform = "day"

# Partition by region
[[iceberg.partition_spec]]
source_field = "region"
transform = "identity"

# Bucket by user_id
[[iceberg.partition_spec]]
source_field = "user_id"
transform = "bucket[16]"

Buffer Configuration​

[buffer]​

OptionTypeRequiredDefaultDescription
ttl_secondsIntegerNo60Time-to-live for buffered records
max_size_mbIntegerNo500Maximum buffer size in MB
flush_interval_secondsIntegerNo30Time-based flush trigger
flush_batch_sizeIntegerNo10000Count-based flush trigger
memory_alignment_bytesIntegerNo64Memory alignment for SIMD (power of 2)

Flush Triggers​

The buffer flushes to Iceberg when ANY of these conditions is met:

  1. Time elapsed since last flush exceeds flush_interval_seconds
  2. Record count exceeds flush_batch_size
  3. Buffer size exceeds max_size_mb

Memory Alignment​

Set memory_alignment_bytes to match your CPU's SIMD width:

  • 64 (default): AVX-512, most modern x86_64
  • 32: AVX2
  • 16: SSE

Transaction Log Configuration​

[transaction_log]​

OptionTypeRequiredDefaultDescription
log_dirStringNo"./transaction_logs"Directory for log files
checkpoint_interval_entriesIntegerNo10000Checkpoint every N entries
checkpoint_interval_secondsIntegerNo300Checkpoint every N seconds
max_log_filesIntegerNo10Maximum log files to retain

Notes​

  • Transaction log records are part of K2I's exactly-once-style durability design
  • Checkpoints create snapshots of system state for faster recovery
  • Log files are automatically rotated based on entry count or time
  • Each entry includes CRC32 checksum for integrity verification
  • Entries are flushed, but not every entry is fsynced individually; see Production Readiness

Maintenance Configuration​

[maintenance]​

OptionTypeRequiredDefaultDescription
compaction_enabledBooleanNotrueEnable compaction task behavior
compaction_interval_secondsIntegerNo3600Compaction run interval
compaction_threshold_mbIntegerNo100Files smaller than this are compaction candidates
compaction_target_mbIntegerNo512Target size for compacted files
snapshot_expiration_enabledBooleanNotrueEnable snapshot expiration task behavior
snapshot_retention_daysIntegerNo7Keep snapshots for N days
orphan_cleanup_enabledBooleanNotrueEnable orphan file cleanup task behavior
orphan_retention_daysIntegerNo3Safety buffer before deleting orphans

Compaction​

Compaction merges small Parquet files into larger ones for better query performance:

  • Files smaller than compaction_threshold_mb are candidates
  • Multiple files are merged until reaching compaction_target_mb
  • Scheduler wiring should be reviewed for each deployment before relying on unattended maintenance

Snapshot Expiration​

Removes old Iceberg snapshots:

  • Keeps snapshots younger than snapshot_retention_days
  • Reduces metadata bloat
  • Does not delete data files still referenced by other snapshots
  • Scheduler wiring should be reviewed for each deployment before relying on unattended expiration

Orphan Cleanup​

Removes unreferenced data files:

  • Files not referenced by any snapshot
  • Must be older than orphan_retention_days (safety buffer)
  • Prevents storage cost from abandoned files
  • Scheduler wiring should be reviewed for each deployment before relying on unattended cleanup

Monitoring Configuration​

[monitoring]​

OptionTypeRequiredDefaultDescription
metrics_portIntegerNo9090Prometheus metrics port
health_portIntegerNo8080Health check endpoint port
log_levelStringNo"info"Log level
log_formatStringNo"json"Log format

Log Levels​

LevelDescription
traceVery detailed debugging information
debugDebugging information
infoInformational messages (recommended for production)
warnWarning messages
errorError messages only

Log Formats​

FormatDescription
jsonStructured JSON logs (recommended for production)
textHuman-readable text logs (recommended for development)

RPC Configuration​

[rpc]​

Controls the optional Unix socket read-state RPC server used by local readers that need a consistent hot/cold table view.

OptionTypeRequiredDefaultDescription
enabledBooleanNofalseStart the local read-state RPC server
socket_pathStringNo"./run/k2i.sock"Unix socket path
read_timeout_msIntegerNo1000Maximum wait for requested read state
max_concurrent_scansIntegerNo64Maximum pinned scans
scan_ttl_secondsIntegerNo300TTL for abandoned scans
max_frame_bytesIntegerNo67108864Maximum RPC frame size

The v1 protocol exposes Health, ListTables, GetTableSchema, ScanTableBegin, and ScanTableEnd. ScanTableBegin returns committed Parquet file references plus hot Arrow IPC bytes for rows not yet visible in cold storage. Clients must call ScanTableEnd to release scan pins.


Environment Variable Substitution​

Configuration values can reference environment variables:

[kafka.security]
sasl_username = "${KAFKA_USERNAME}"
sasl_password = "${KAFKA_PASSWORD}"

[iceberg]
aws_access_key_id = "${AWS_ACCESS_KEY_ID}"
aws_secret_access_key = "${AWS_SECRET_ACCESS_KEY}"

CLI Overrides​

Some configuration options can be overridden via CLI flags:

k2i ingest \
--config config.toml \
--bootstrap-servers "kafka1:9092,kafka2:9092" \
--topic "production-events" \
--consumer-group "k2i-prod"

CLI flags take precedence over config file values.


Configuration Validation​

Validate your configuration before running:

k2i validate --config config.toml

Common validation checks:

  • Required fields are present
  • Kafka bootstrap servers are non-empty
  • Protobuf Schema Registry settings are valid when kafka.format.type = "protobuf"
  • Iceberg catalog type is valid
  • Memory alignment is a power of 2
  • RPC scan/frame limits are greater than zero
  • Schema update interval is greater than zero
  • Port numbers are in valid range
  • Paths are accessible

Example Configurations​

Minimal Configuration​

[kafka]
bootstrap_servers = ["localhost:9092"]
topic = "events"
consumer_group = "k2i"

[iceberg]
catalog_type = "rest"
rest_uri = "http://localhost:8181"
warehouse_path = "s3://bucket/warehouse"
database_name = "default"
table_name = "events"

Production AWS Configuration​

[kafka]
bootstrap_servers = ["kafka1.prod:9092", "kafka2.prod:9092", "kafka3.prod:9092"]
topic = "events"
consumer_group = "k2i-production"
batch_size = 5000
batch_timeout_ms = 1000
max_poll_interval_ms = 600000

[kafka.security]
protocol = "SASL_SSL"
sasl_mechanism = "SCRAM-SHA-512"
sasl_username = "${KAFKA_USERNAME}"
sasl_password = "${KAFKA_PASSWORD}"
ssl_ca_location = "/etc/kafka/ca.pem"

[iceberg]
catalog_type = "glue"
warehouse_path = "s3://data-lake-prod/iceberg/"
database_name = "analytics"
table_name = "events"
target_file_size_mb = 512
compression = "zstd"
aws_region = "us-east-1"

[[iceberg.partition_spec]]
source_field = "event_timestamp"
transform = "day"

[buffer]
ttl_seconds = 120
max_size_mb = 2000
flush_interval_seconds = 60
flush_batch_size = 50000

[transaction_log]
log_dir = "/var/lib/k2i/txlog"
checkpoint_interval_entries = 50000
checkpoint_interval_seconds = 600
max_log_files = 20

[maintenance]
compaction_enabled = true
compaction_interval_seconds = 7200
compaction_threshold_mb = 128
compaction_target_mb = 512
snapshot_expiration_enabled = true
snapshot_retention_days = 30
orphan_cleanup_enabled = true
orphan_retention_days = 7

[monitoring]
metrics_port = 9090
health_port = 8080
log_level = "info"
log_format = "json"

Local Development with MinIO​

[kafka]
bootstrap_servers = ["localhost:9092"]
topic = "dev-events"
consumer_group = "k2i-dev"
batch_size = 100
auto_offset_reset = "earliest"

[iceberg]
catalog_type = "rest"
rest_uri = "http://localhost:8181"
warehouse_path = "s3://dev-warehouse/"
database_name = "dev"
table_name = "events"
target_file_size_mb = 32
compression = "snappy"
s3_endpoint = "http://localhost:9000"
aws_region = "us-east-1"
aws_access_key_id = "minioadmin"
aws_secret_access_key = "minioadmin"

[buffer]
ttl_seconds = 30
max_size_mb = 50
flush_interval_seconds = 10
flush_batch_size = 100

[transaction_log]
log_dir = "./dev-txlog"

[maintenance]
compaction_enabled = false
snapshot_expiration_enabled = false
orphan_cleanup_enabled = false

[monitoring]
metrics_port = 9090
health_port = 8080
log_level = "debug"
log_format = "text"