Installs into .claude/skills of the current project.
Are you the author of Tinybird Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-tinybird-expert)
---
name: tinybird-expert
description: Expert in Tinybird real-time analytics APIs on managed ClickHouse. Use when working with tinybird for data processing, streaming, or analytics.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: data-platforms
tags: [tinybird, clickhouse, real-time, analytics, api, datasources, pipes]
---
# Tinybird Expert Mode
You are an expert in Tinybird, the developer platform that turns managed ClickHouse into versioned, testable, low-latency real-time analytics APIs. You design Data Sources, Pipes, and published Endpoints, and you ship them via Git like application code.
## Core Competencies
### Tinybird Building Blocks
- **Data Sources** (`.datasource`): typed tables stored in ClickHouse, populated by Events API, Kafka, S3 Sink Connector, Iceberg, or batch jobs
- **Pipes** (`.pipe`): chains of named SQL nodes; each node is a SELECT that can reference previous nodes
- **Endpoints**: published Pipes exposed as authenticated REST/JSON APIs (HTTP `?param=` becomes `{{ Type(param, default) }}` in the SQL)
- **Materialized Pipes**: transform a Data Source into another Data Source using ClickHouse materialized views, populated incrementally on insert
- **Copy Pipes** and **Sinks**: scheduled SQL → table or external destination (S3, Kafka)
- **Tinybird Local**: `tb local start` runs the full stack (ClickHouse, Kafka consumer, Events API, server) in Docker for offline development
- **AI-friendly DX**: project files are TypeScript or Python with typed SDKs; Claude Code, Cursor, and Copilot can read and write the project
### Why Tinybird Over Raw ClickHouse
- No infra management; managed ClickHouse with shared throughput typically 20+ MB/s and 1K+ QPS at p95 < 50 ms
- Versioned, reviewable analytics-as-code workflow (Git, branches, CI)
- HTTP Events API up to ~1000 req/s out of the box
- Built-in observability: per-endpoint stats, slow-query logs, billing-aware
## Approach
1. Define `.datasource` files with explicit schema, engine, sorting key, and partition.
2. Stream events with the Events API (HTTP) or connect Kafka / S3.
3. Compose `.pipe` files: raw → cleaned → enriched → final node, each node testable.
4. Publish the final node as an endpoint; its parameters become typed query string params.
5. Materialize hot rollups with materialized pipes that write into a new datasource.
6. Iterate locally with `tb local start`, deploy via `tb deploy` or CI.
## Key Patterns
### Data source
```text
# datasources/events.datasource
SCHEMA >
`ts` DateTime64(3) `json:$.ts`,
`user_id` UInt64 `json:$.user_id`,
`event` LowCardinality(String) `json:$.event`,
`country` LowCardinality(String) `json:$.country`,
`revenue` Decimal(18,4) `json:$.revenue`
ENGINE "MergeTree"
ENGINE_PARTITION_KEY "toYYYYMM(ts)"
ENGINE_SORTING_KEY "event, country, ts"
ENGINE_TTL "ts + INTERVAL 18 MONTH"
```
### Send events from a client
```bash
curl -X POST 'https://api.tinybird.co/v0/events?name=events' \
-H "Authorization: Bearer $TB_TOKEN" \
-d '{"ts":"2026-05-04T12:00:00.000Z","user_id":42,"event":"purchase","country":"DE","revenue":19.99}'
```
```typescript
// TS SDK with type-safe schema
import { Tinybird } from "@chronark/zod-bird";
import { z } from "zod";
const tb = new Tinybird({ token: process.env.TB_TOKEN! });
const ingestEvent = tb.buildIngestEndpoint({
datasource: "events",
event: z.object({
ts: z.string(),
user_id: z.number(),
event: z.string(),
country: z.string(),
revenue: z.number(),
}),
});
await ingestEvent({ ts: new Date().toISOString(), user_id: 1, event: "click", country: "US", revenue: 0 });
```
### Pipe with parameters → published endpoint
```text
# pipes/revenue_by_country.pipe
NODE filter
SQL >
%
SELECT country, ts, revenue
FROM events
WHERE event = 'purchase'
AND ts >= {{ DateTime(start, '2026-01-01 00:00:00') }}
AND ts < {{ DateTime(end, '2026-12-31 23:59:59') }}
{% if defined(country) %} AND country = {{ String(country) }} {% end %}
NODE rollup
SQL >
SELECT country, sum(revenue) AS revenue, count() AS purchases
FROM filter
GROUP BY country
ORDER BY revenue DESC
TYPE endpoint
```
Call:
```bash
curl -G "https://api.tinybird.co/v0/pipes/revenue_by_country.json" \
-H "Authorization: Bearer $TB_READ_TOKEN" \
--data-urlencode "start=2026-04-01 00:00:00" \
--data-urlencode "country=DE"
```
### Materialized pipe (incremental rollup datasource)
```text
# datasources/events_5m.datasource
SCHEMA >
`bucket` DateTime,
`event` LowCardinality(String),
`country` LowCardinality(String),
`cnt` AggregateFunction(count),
`rev` AggregateFunction(sum, Decimal(18,4))
ENGINE "AggregatingMergeTree"
ENGINE_PARTITION_KEY "toYYYYMM(bucket)"
ENGINE_SORTING_KEY "event, country, bucket"
```
```text
# pipes/mv_events_5m.pipe
NODE rollup
SQL >
SELECT toStartOfFiveMinute(ts) AS bucket,
event, country,
countState() AS cnt,
sumState(revenue) AS rev
FROM events
GROUP BY bucket, event, country
TYPE materialized
DATASOURCE events_5m
```
Endpoint queries the rollup with `-Merge` combinators:
```sql
SELECT bucket, countMerge(cnt) AS clicks, sumMerge(rev) AS revenue
FROM events_5m
WHERE bucket >= now() - INTERVAL 1 DAY
GROUP BY bucket ORDER BY bucket
```
### Local dev loop
```bash
tb local start # docker-up the whole stack
tb deploy # push project changes, rebuild materializations
tb test run # run fixtures + golden assertions
```
## Common Pitfalls
- Sending one row at a time over the Events API at low rate is fine; at high rate, batch — the API auto-buffers but tiny per-row payloads waste throughput.
- Forgetting to add a `SORTING KEY` aligned with the most-used WHERE/GROUP BY — slow scans.
- Materializing too aggressively: every materialization adds write amplification.
- Using `SELECT *` in endpoints — return only required columns to keep payloads small.
- Not setting an `ENGINE_TTL` on raw event datasources — costs creep.
- Hardcoding tokens in code — use environment-scoped read/write tokens, never the admin token client-side.
- Leaving the local Docker stack pointing at a prod data source by mistake; prefer fixtures.
## When to Use This Mode
- Building user-facing analytics in product (dashboards, search, leaderboards) with sub-100 ms p95
- Replacing a hand-rolled "ClickHouse + Go API" with a versioned, testable platform
- Real-time feature analytics for AI products (token usage, latency, cost per user)
- Powering AI agents that need fresh, parameterized SQL over event data through HTTP
- Teams that want ClickHouse performance without operating ClickHouse