Skip to main content
Type validators define column schemas for Tinybird datasources. They provide full TypeScript type inference and map directly to ClickHouse column types.

Basic Usage

import { t } from '@tinybirdco/sdk';

const schema = {
  id: t.string(),
  count: t.int32(),
  timestamp: t.dateTime(),
  tags: t.array(t.string()),
  metadata: t.json(),
};

String Types

t.string()

Variable length UTF-8 string.
name: t.string()

t.fixedString(length)

Fixed length string, padded with null bytes.
code: t.fixedString(3) // 3-character country code

t.uuid()

16-byte universally unique identifier.
id: t.uuid()

Integer Types

t.int8()

Signed 8-bit integer (-128 to 127)

t.int16()

Signed 16-bit integer

t.int32()

Signed 32-bit integer

t.int64()

Signed 64-bit integer

t.int128()

Signed 128-bit integer (bigint)

t.int256()

Signed 256-bit integer (bigint)

t.uint8()

Unsigned 8-bit integer (0 to 255)

t.uint16()

Unsigned 16-bit integer

t.uint32()

Unsigned 32-bit integer

t.uint64()

Unsigned 64-bit integer

t.uint128()

Unsigned 128-bit integer (bigint)

t.uint256()

Unsigned 256-bit integer (bigint)

Float Types

t.float32()

32-bit floating point number.
temperature: t.float32()

t.float64()

64-bit floating point number (double precision).
amount: t.float64()

t.decimal(precision, scale)

Fixed-point decimal number.
price: t.decimal(10, 2) // 10 total digits, 2 decimal places

Boolean

t.bool()

Boolean value (true/false).
is_active: t.bool()

Date/Time Types

t.date()

Date in YYYY-MM-DD format.
birth_date: t.date() // "2024-01-15"

t.date32()

Date in YYYY-MM-DD format with extended date range.
archive_date: t.date32()

t.dateTime(timezone?)

DateTime in YYYY-MM-DD HH:MM:SS format.
created_at: t.dateTime() // "2024-01-15 10:30:00"
updated_at: t.dateTime('UTC') // with timezone

t.dateTime64(precision?, timezone?)

DateTime with fractional seconds.
timestamp: t.dateTime64(3) // "2024-01-15 10:30:00.123"
logged_at: t.dateTime64(6, 'America/New_York') // microseconds with timezone
Precision can be 0-9 (defaults to 3 for milliseconds).

Complex Types

t.array(element)

Array of elements of type T.
tags: t.array(t.string())
scores: t.array(t.int32())

t.tuple(...elements)

Tuple of heterogeneous types.
coordinates: t.tuple(t.float64(), t.float64())

t.map(keyType, valueType)

Dictionary/map type.
metadata: t.map(t.string(), t.string())
counters: t.map(t.string(), t.int32())

t.json()

Semi-structured JSON data.
properties: t.json()

Enum Types

t.enum8(...values)

Enumeration stored as Int8.
status: t.enum8('pending', 'active', 'completed')

t.enum16(...values)

Enumeration stored as Int16.
priority: t.enum16('low', 'medium', 'high', 'critical')

Special Types

t.ipv4()

IPv4 address
ip: t.ipv4()

t.ipv6()

IPv6 address
ip: t.ipv6()

Aggregate Function States

t.simpleAggregateFunction(func, type)

For materialized views with simple aggregates (sum, min, max, any, anyLast).
total: t.simpleAggregateFunction('sum', t.uint64())
max_value: t.simpleAggregateFunction('max', t.float64())

t.aggregateFunction(func, type)

For materialized views with complex aggregates.
unique_users: t.aggregateFunction('uniq', t.string())
avg_value: t.aggregateFunction('avg', t.float64())

Modifiers

.nullable()

Make a column nullable.
country: t.string().nullable()
// TypeScript type: string | null

.lowCardinality()

Apply LowCardinality optimization for columns with few unique values (improves performance for strings with < 10,000 unique values).
category: t.string().lowCardinality()
status: t.string().lowCardinality().nullable()

.default(value)

Set a default value for the column.
status: t.string().default('pending')
count: t.int32().default(0)

.codec(codec)

Set a compression codec for the column.
payload: t.string().codec('ZSTD(3)')
value: t.float64().codec('Delta, LZ4')

.jsonPath(path)

Set an explicit JSON path for extraction (overrides autogenerated path).
user_id: t.string().jsonPath('$.user.id')

Custom Type Brands

You can use TypeScript branded types for narrower type inference:
type UserId = string & { readonly __brand: 'UserId' };
type Timestamp = string & { readonly __brand: 'Timestamp' };

const schema = {
  user_id: t.string<UserId>(),
  created_at: t.dateTime<Timestamp>(),
};

Complete Example

import { defineDatasource, t, engine, type InferRow } from '@tinybirdco/sdk';

export const pageViews = defineDatasource('page_views', {
  description: 'Page view tracking data',
  schema: {
    timestamp: t.dateTime(),
    pathname: t.string(),
    session_id: t.string(),
    country: t.string().lowCardinality().nullable(),
    duration_ms: t.int32().nullable(),
    metadata: t.json(),
  },
  engine: engine.mergeTree({
    sortingKey: ['pathname', 'timestamp'],
    partitionKey: 'toYYYYMM(timestamp)',
    ttl: 'timestamp + INTERVAL 90 DAY',
  }),
});

// Export row type for ingestion
export type PageViewsRow = InferRow<typeof pageViews>;
// { timestamp: string, pathname: string, session_id: string, country: string | null, duration_ms: number | null, metadata: unknown }

Type Inference Helpers

import { type InferType, type TinybirdType } from '@tinybirdco/sdk';

const userIdValidator = t.string();

type UserIdType = InferType<typeof userIdValidator>; // string
type UserIdTinybirdType = TinybirdType<typeof userIdValidator>; // "String"

Build docs developers (and LLMs) love