TypeScript SDK resources¶
Use the TypeScript SDK to define Tinybird resources as code with full type inference. You can define datasources, pipes, endpoints, materialized views, copy pipes, and connections in TypeScript and sync them to Tinybird.
Project layout¶
The SDK scaffolds the following files by default:
lib/tinybird.tstinybird.config.mjs
Configure credentials¶
Create a .env.local file in your project root with the Tinybird token and host:
TINYBIRD_TOKEN=p.your_token_here TINYBIRD_URL=https://api.tinybird.co
Datasources¶
Define datasources with schemas and engines:
import { defineDatasource, engine, t, 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(),
},
engine: engine.mergeTree({
sortingKey: ["pathname", "timestamp"],
}),
});
export type PageViewsRow = InferRow<typeof pageViews>;
Endpoints¶
Define API endpoints:
import {
defineEndpoint,
node,
p,
t,
type InferParams,
type InferOutputRow,
} from "@tinybirdco/sdk";
export const topPages = defineEndpoint("top_pages", {
description: "Get the most visited pages",
params: {
start_date: p.dateTime(),
end_date: p.dateTime(),
limit: p.int32().optional(10),
},
nodes: [
node({
name: "aggregated",
sql: `
SELECT pathname, count() AS views
FROM page_views
WHERE timestamp >= {{DateTime(start_date)}}
AND timestamp <= {{DateTime(end_date)}}
GROUP BY pathname
ORDER BY views DESC
LIMIT {{Int32(limit, 10)}}
`,
}),
],
output: {
pathname: t.string(),
views: t.uint64(),
},
});
export type TopPagesParams = InferParams<typeof topPages>;
export type TopPagesOutput = InferOutputRow<typeof topPages>;
Pipes¶
Define internal pipes that are not exposed as API endpoints:
import { definePipe, node, p } from "@tinybirdco/sdk";
export const filteredEvents = definePipe("filtered_events", {
description: "Filter events by date range",
params: {
start_date: p.dateTime(),
end_date: p.dateTime(),
},
nodes: [
node({
name: "filtered",
sql: `
SELECT * FROM events
WHERE timestamp >= {{DateTime(start_date)}}
AND timestamp <= {{DateTime(end_date)}}
`,
}),
],
});
Materialized views¶
Use materialized views to populate derived datasources:
import {
defineDatasource,
defineMaterializedView,
node,
t,
engine,
} from "@tinybirdco/sdk";
export const dailyStats = defineDatasource("daily_stats", {
schema: {
date: t.date(),
pathname: t.string(),
views: t.simpleAggregateFunction("sum", t.uint64()),
},
engine: engine.aggregatingMergeTree({
sortingKey: ["date", "pathname"],
}),
});
export const dailyStatsMv = defineMaterializedView("daily_stats_mv", {
datasource: dailyStats,
nodes: [
node({
name: "aggregate",
sql: `
SELECT toDate(timestamp) AS date, pathname, count() AS views
FROM page_views
GROUP BY date, pathname
`,
}),
],
});
Copy pipes¶
Use copy pipes for snapshots or scheduled exports:
import { defineCopyPipe, node } from "@tinybirdco/sdk";
export const dailySnapshot = defineCopyPipe("daily_snapshot", {
datasource: dailyStats,
schedule: "0 0 * * *",
mode: "append",
nodes: [
node({
name: "snapshot",
sql: `SELECT * FROM daily_stats WHERE date = today() - 1`,
}),
],
});
Connections¶
Define connector connections and reference them in datasources:
import { defineKafkaConnection, defineDatasource, engine, t } from "@tinybirdco/sdk";
export const eventsKafka = defineKafkaConnection("events_kafka", {
bootstrapServers: "kafka.example.com:9092",
securityProtocol: "SASL_SSL",
saslMechanism: "PLAIN",
key: '{{ tb_secret("KAFKA_KEY") }}',
secret: '{{ tb_secret("KAFKA_SECRET") }}',
});
export const kafkaEvents = defineDatasource("kafka_events", {
schema: {
timestamp: t.dateTime(),
payload: t.string(),
},
engine: engine.mergeTree({
sortingKey: ["timestamp"],
}),
kafka: {
connection: eventsKafka,
topic: "events",
groupId: "events-consumer",
},
});
Next steps¶
- Review the SDK CLI: TypeScript SDK CLI commands
- Follow the SDK quickstart: Quick start: TypeScript SDK