Quick start: TypeScript SDK

This quickstart walks through creating a Tinybird project using the TypeScript SDK. You define datasources and endpoints in TypeScript, sync them to Tinybird, and use a typed client for ingest and queries.

Before you begin

To get started, you need the following:

  • Node.js 20 LTS or later
  • TypeScript 4.9 or later

Install the SDK

We recommend installing the SDK globally so you can run the tinybird CLI directly.

pnpm add @tinybirdco/sdk --global

You can also add it just to your repository:

pnpm add @tinybirdco/sdk

Initialize a Tinybird TypeScript project

Run the Tinybird SDK CLI to scaffold the project:

npx tinybird init

During initialization, the CLI authenticates you against Tinybird Cloud and can optionally add CI/CD workflow files.

This creates:

  • tinybird.config.json configuration file
  • src/tinybird/datasources.ts for Data Source definitions
  • src/tinybird/pipes.ts for Pipe, Copy, Materializations, and Endpoint definitions
  • src/tinybird/client.ts for the typed client

Configure your Tinybird token

Create a .env.local file with your Tinybird token if not exists yet:

TINYBIRD_TOKEN=p.your_token_here

The CLI reads .env.local automatically.

Define a Data Source

Add a Data Source definition in src/tinybird/datasources.ts:

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>;

Define an API Endpoint

Add a Pipe definition in src/tinybird/pipes.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(),
    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>;

Create the typed client

Wire up the client in src/tinybird/client.ts:

import { createTinybirdClient } from "@tinybirdco/sdk";
import { pageViews, type PageViewsRow } from "./datasources";
import { topPages, type TopPagesParams, type TopPagesOutput } from "./pipes";

export const tinybird = createTinybirdClient({
  datasources: { pageViews },
  pipes: { topPages },
});

export type { PageViewsRow, TopPagesParams, TopPagesOutput };
export { pageViews, topPages };

Build the project

Run a build to push your current resources to Tinybird:

tinybird build

If you want your changes to sync automatically while you work, run dev mode instead:

tinybird dev

Choose a development flow

Your default target (local or branch) is set in tinybird.config.json. You can override it with flags on the command line.

By default, tinybird dev syncs to a Tinybird feature branch. You can also work against Tinybird Local for isolated development.

tinybird dev --local

If you haven't installed Tinybird Local yet, follow Install Tinybird Local.

When you're ready to promote changes:

  • Use tinybird build to push to a branch (good for review or CI).
  • To deploy to Tinybird Cloud main workspace (production) we strongly recommend CD, but you can use tinybird deploy directly.

Ingest data and query

Use the typed client in your application code:

import { tinybird, type PageViewsRow } from "@tinybird/client";

await tinybird.ingest.pageViews({
  timestamp: new Date(),
  pathname: "/home",
  session_id: "abc123",
  country: "US",
});

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);
});

Next steps

Updated