Quickstart: TypeScript SDK¶
This quickstart walks through creating a Tinybird project using the TypeScript SDK. You define Data Sources and Endpoints in TypeScript, sync them to Tinybird, and use a typed client for ingest and queries.
Looking for other ways to start? See Quickstarts.
If you use a coding agent like Cursor, Claude Code, Amp, or Open Code, install Tinybird agent skills so your agent understands Tinybird project structure and workflows:
npx skills add tinybirdco/tinybird-agent-skills
Before you begin¶
To get started, you need the following:
- Node.js 20 LTS or later
- TypeScript 4.9 or later
SDK Installation¶
We recommend installing the SDK globally so you can run the tinybird CLI directly.
pnpm add -g @tinybirdco/sdk
You can also add it just to your repository:
pnpm add @tinybirdco/sdk
To follow the quickstart, install it in the repository so that commands work exactly as they are in the examples.
Initialize a Tinybird TypeScript project¶
Create a new directory and initialize the project:
mkdir tinybird-typescript-quickstart cd tinybird-typescript-quickstart git init pnpm add @tinybirdco/sdk npx tinybird init
During initialization, the CLI authenticates you against Tinybird Cloud and can optionally add CI/CD workflow files.
This creates:
tinybird.config.jsonconfiguration filelib/tinybird.tsfor Data Sources, Pipes, Connectors, and Client definitions.env.localfor authentication against your Tinybird Cloud Workspace
Check your config file¶
In tinybird.config.json, the default "include" is lib/tinybird.ts to generate resources from that file. The default "devMode" is "branches" to develop in Tinybird Cloud Branches, although you can use "local" too with Tinybird Local.
{
"include": [
"lib/tinybird.ts"
],
"token": "${TINYBIRD_TOKEN}",
"baseUrl": "${TINYBIRD_URL}",
"devMode": "branches"
}
Check your Tinybird token¶
Create a .env.local file with your Tinybird token if it doesn't exist yet:
TINYBIRD_TOKEN=p.your_token_here TINYBIRD_URL=https://api.tinybird.co
The CLI reads .env.local automatically.
Inspect resource definitions¶
Data sources¶
Check the Data Source definition in lib/tinybird.ts. The schema and engine stay the same regardless of how you ingest data. The difference is how data arrives: via the Events API, from a Kafka topic, or from an S3 bucket.
import { defineDatasource, engine, t, type InferRow } from "@tinybirdco/sdk";
export const pageViews = defineDatasource("page_views", {
description: "Page view tracking data",
schema: {
timestamp: t.dateTime(),
session_id: t.string(),
pathname: t.string(),
referrer: t.string().nullable(),
},
engine: engine.mergeTree({
sortingKey: ["pathname", "timestamp"],
}),
});
export type PageViewsRow = InferRow<typeof pageViews>;
API Endpoints¶
Check the API Endpoint definition in lib/tinybird.ts:
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().describe("Start of date range"),
end_date: p.dateTime().describe("End of date range"),
limit: p.int32().optional(10).describe("Number of results"),
},
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>;
Typed client¶
Check the client in lib/tinybird.ts:
import { Tinybird } from "@tinybirdco/sdk";
export const tinybird = new Tinybird({
datasources: { pageViews },
pipes: { topPages },
});
Build the project¶
Check out a new git branch:
git add tinybird.config.json && git commit -m "Initial commit" && git checkout -b tinybird-intro
Run a build to create your resources in your Tinybird development environment:
npx tinybird build
If you want your changes to sync automatically while you work, run dev mode instead:
npx tinybird dev
About the development flow¶
Your default target (local or branch) is set in tinybird.config.json. You can override it with flags on the command line.
tinybird build syncs to a Tinybird branch, either in Cloud or in Tinybird Local.
You can also pass a flag to explicitly use the desired development environment.
npx tinybird build --local # Tinybird Local Branches # or npx tinybird build --branch # Tinybird Cloud Branches
If you haven't installed Tinybird Local yet, follow Install Tinybird Local.
When you're ready to promote changes:
- Use
tinybird buildto push to a branch (good for review or CI). - To deploy to your main Tinybird Cloud Workspace, we strongly recommend CI/CD, but you can use
tinybird deploydirectly.
Git integration¶
You may have noticed that the quickstart example had a git checkout -b tinybird-intro. If Tinybird detects you are in a Git repository, it creates a branch with the git branch name in your Tinybird development environment.
Ingest data and query¶
Ingest¶
Use the typed client to send events via the Events API:
import { tinybird } from "./lib/tinybird";
await tinybird.ingest.pageViews({
timestamp: new Date(),
pathname: "/home",
session_id: "abc123",
referrer: "https://google.com",
});
If you configured a Kafka or S3 connector, data is ingested automatically after you deploy. You don't need to call ingest manually.
Query¶
Query the endpoint from your application code:
const result = await tinybird.query.topPages({
start_date: new Date("2026-01-01"),
end_date: new Date(),
limit: 5,
});
result.data.forEach((row) => {
console.log(row.pathname, row.views);
});
Iterate in a branch¶
Add a materialized view in another branch, test the app against that branch, and deploy to Tinybird Cloud when you're finished.
git checkout -b materialization
Edit lib/tinybird.ts to add a new Data Source, a new materialized view, and update the Endpoint to read from the materialized view.
import {
defineDatasource,
defineEndpoint,
defineMaterializedView,
engine,
node,
p,
t,
} from "@tinybirdco/sdk";
export const pageViews = defineDatasource("page_views", {
description: "Page view tracking data",
schema: {
timestamp: t.dateTime(),
session_id: t.string(),
pathname: t.string(),
referrer: t.string().nullable(),
},
engine: engine.mergeTree({
sortingKey: ["pathname", "timestamp"],
}),
});
export const dailyPageViews = defineDatasource("daily_page_views_ds", {
description: "Daily page view counts populated by a materialized view",
schema: {
date: t.date(),
pathname: t.string(),
views: t.simpleAggregateFunction("sum", t.uint64()),
},
engine: engine.aggregatingMergeTree({
sortingKey: ["date", "pathname"],
}),
});
export const dailyPageViewsMv = defineMaterializedView("daily_page_views_mv", {
datasource: dailyPageViews,
nodes: [
node({
name: "aggregate",
sql: `
SELECT
toDate(timestamp) AS date,
pathname,
count() AS views
FROM page_views
GROUP BY date, pathname
`,
}),
],
});
export const topPages = defineEndpoint("top_pages", {
description: "Get the most visited pages from MV-backed datasource",
params: {
start_date: p.dateTime(),
end_date: p.dateTime(),
limit: p.int32().optional(10),
},
nodes: [
node({
name: "aggregated",
sql: `
SELECT
pathname,
sum(views) AS views
FROM daily_page_views_ds
WHERE date >= toDate({{DateTime(start_date)}})
AND date <= toDate({{DateTime(end_date)}})
GROUP BY pathname
ORDER BY views DESC
LIMIT {{Int32(limit, 10)}}
`,
}),
],
output: {
pathname: t.string(),
views: t.uint64(),
},
});
Build against the branch:
npx tinybird build
Once validated, you can deploy to Tinybird Cloud with npx tinybird deploy if you haven't set up a CI/CD script.
Next steps¶
- Review the SDK repository for advanced usage. See tinybird-sdk-typescript.
- Review the TypeScript SDK CLI reference. See TypeScript SDK CLI commands.
- Learn about core Tinybird concepts. See Core concepts.
- Configure deployments and branches. See Development workflow.