For the complete documentation index, see llms.txt. This page is also available as Markdown.

Proto Annotations

When the output module of a SQL sink does not produce DatabaseChanges, the sink derives the database schema from the module's protobuf definition (relational mappings). This page is the reference for the annotations and type mappings driving that schema generation. For a guided walkthrough, see Using Relational Mappings.

Annotations come from sf/substreams/sink/sql/schema/v1/schema.proto:

import "sf/substreams/sink/sql/schema/v1/schema.proto";

Table Options

Annotate a message with (schema.table) to control the table it maps to:

message MyTable {
  option (schema.table) = {
    name: "my_table"
    clickhouse_table_options: {
      order_by_fields: [{name: "id"}]
      partition_fields: [{name: "created_date", function: toYYYYMM}]
      index_fields: [{
        field_name: "status"
        name: "status_idx"
        type: bloom_filter
        granularity: 4
      }]
    }
  };
}

Child Tables

Nested messages can map to child tables with a foreign key to their parent:

Field Options

Annotate individual fields with (schema.field):

Type Mappings

Protobuf types map to SQL types as follows:

Protobuf Type
PostgreSQL Type
ClickHouse Type

string

VARCHAR(255)

String

int32, sint32, sfixed32

INTEGER

Int32

int64, sint64, sfixed64

BIGINT

Int64

uint32, fixed32

NUMERIC

UInt32

uint64, fixed64

NUMERIC

UInt64

float

DECIMAL

Float32

double

DOUBLE PRECISION

Float64

bool

BOOLEAN

Bool

bytes

TEXT

String

google.protobuf.Timestamp

TIMESTAMP

DateTime

repeated <type>

<type>[]

Array(<type>)

Extended Numeric Types

String fields holding numeric values larger than native integer ranges can be converted with the convertTo field option:

String Conversion Type
PostgreSQL Type
ClickHouse Type
Use Case

Int128

NUMERIC(39,0)

Int128

128-bit signed integers

UInt128

NUMERIC(39,0)

UInt128

128-bit unsigned integers

Int256

NUMERIC(78,0)

Int256

256-bit signed integers

UInt256

NUMERIC(78,0)

UInt256

256-bit unsigned integers

Decimal128

NUMERIC(38,scale)

Decimal128(precision,scale)

128-bit decimals

Decimal256

NUMERIC(76,scale)

Decimal256(precision,scale)

256-bit decimals

Typical uses: token amounts exceeding the uint64 range, high-precision decimal arithmetic, 256-bit hashes or identifiers stored as strings.

ClickHouse-Specific Options

ClickHouse tables require the clickhouse_table_options annotation on each table: at minimum order_by_fields, optionally partition_fields and index_fields.

Table Engine

Tables are created with the ReplacingMergeTree engine:

This provides automatic deduplication based on the _version_ column and soft deletes through the _deleted_ column for handling chain reorgs.

Querying with Reorg Safety

Filter out deleted records for current-state queries:

For aggregations (including materialized views), use the additive pattern so reorg corrections cancel out:

📚 Deep Dive: See the ClickHouse Showcase and its Deep Dive for a production-grade example with materialized views and partitioning strategies.

Performance Flags

For fast initial imports:

  • --no-constraints: skip creating database constraints

  • --block-batch-size: number of blocks to process at a time (default: 25)

Troubleshooting

  1. Proto import errors: ensure all required proto files are in your import paths

  2. Schema annotation errors: verify you import sf/substreams/sink/sql/schema/v1/schema.proto

  3. Module output type errors: ensure your Substreams module outputs the expected proto message

  4. String conversion errors: verify that string fields marked for numeric conversion contain valid numeric values

  5. ClickHouse partition errors: ensure partition functions match your data types (e.g. toYYYYMM for timestamps)

Last updated

Was this helpful?