---
title: Pipes
meta:
    description: Pipes help you to bring your SQL queries together to achieve a purpose, like publishing an endpoint.
---

# Pipes

A pipe is a collection of one or more SQL queries. Each query is called a node.

Use Pipes to build features over your data. For example, you can write SQL that joins, aggregates, or otherwise transforms your data. Pipes may be internal, that is, just referenced in your project, or they can have different outputs such as API Endpoints, Sinks, Materialized Views, and Copy Jobs.

{% snippet title="nodes" /%}

Pipes are defined with `.pipe` files in regular projects, in `.ts` files with the TypeScript SDK, or in `.py` files with the Python SDK.

SQL nodes can use Tinybird's [templating language](/forward/core-concepts/templating-language) for typed parameters, conditional SQL, and environment-specific values.

{% tabs initial="Tinybird CLI" %}
{% tab label="Tinybird CLI" %}

```tb {% title="pipes/events_by_path.pipe" %}
DESCRIPTION >
    Count events by path for a date range

NODE recent_events
SQL >
    %
    SELECT timestamp, pathname
    FROM events
    WHERE timestamp >= {{DateTime(start_date)}}
      AND timestamp <= {{DateTime(end_date)}}

NODE aggregation
SQL >
    SELECT pathname, count() AS events
    FROM recent_events
    GROUP BY pathname
    ORDER BY events DESC
```

{% /tab %}

{% tab label="TypeScript SDK" %}

```ts {% title="tinybird.ts" %}
import { definePipe, node, p } from "@tinybirdco/sdk";

export const eventsByPath = definePipe("events_by_path", {
  description: "Count events by path for a date range",
  params: {
    start_date: p.dateTime(),
    end_date: p.dateTime(),
  },
  nodes: [
    node({
      name: "recent_events",
      sql: `
        SELECT timestamp, pathname
        FROM events
        WHERE timestamp >= {{DateTime(start_date)}}
          AND timestamp <= {{DateTime(end_date)}}
      `,
    }),
    node({
      name: "aggregation",
      sql: `
        SELECT pathname, count() AS events
        FROM recent_events
        GROUP BY pathname
        ORDER BY events DESC
      `,
    }),
  ],
});
```

{% /tab %}

{% tab label="Python SDK" %}

```python {% title="tinybird.py" %}
from tinybird_sdk import define_pipe, node, p

events_by_path = define_pipe("events_by_path", {
    "description": "Count events by path for a date range",
    "params": {
        "start_date": p.date_time(),
        "end_date": p.date_time(),
    },
    "nodes": [
        node({
            "name": "recent_events",
            "sql": """
                SELECT timestamp, pathname
                FROM events
                WHERE timestamp >= {{DateTime(start_date)}}
                  AND timestamp <= {{DateTime(end_date)}}
            """,
        }),
        node({
            "name": "aggregation",
            "sql": """
                SELECT pathname, count() AS events
                FROM recent_events
                GROUP BY pathname
                ORDER BY events DESC
            """,
        }),
    ],
})
```

{% /tab %}
{% /tabs %}

See all syntax options in the [Pipe files reference](/forward/dev-reference/datafiles/pipe-files), [TypeScript SDK reference](/forward/dev-reference/typescript-sdk-resources#pipes), and [Python SDK reference](/forward/dev-reference/python-sdk-resources#pipes).

## Create generic pipes

Generic pipes are internal pipes that you use from other pipes or endpoints. The examples above create generic pipes because they don't declare an output type such as Endpoint, Materialized View, Copy Job, or Sink.

Use generic pipes to split complex SQL into reusable steps or to replace include-file patterns from Classic projects. To publish the result as an API endpoint, see [Endpoints](/forward/core-concepts/api-endpoints).

## Next steps

- Learn about [Endpoints](/forward/core-concepts/api-endpoints).
- Learn about [Copy pipes](/forward/core-concepts/copy-pipes).
- Learn about [Materialized views](/forward/core-concepts/materialized-views).
