---
title: Migrate from Tinybird Classic
meta:
    description: Migrate your project from Tinybird Classic to Tinybird Forward.
---

# Migrate from Tinybird Classic

Tinybird Forward introduces a new way of working with your data projects, with changes to APIs and CLI that may be incompatible with Tinybird Classic. If you're starting a new project, see the [Get started](/forward) guide.

Migrating doesn't move or copy your data. Your tables and their contents stay exactly where they are. Tinybird only restructures how your project is defined on the backend so it can use Forward's features.

## Why migrate to Forward

Forward is a significant evolution of the Tinybird developer experience. Migrating unlocks the following benefits:

- **Deployments**: Project iteration is easier. You ship a new version of the project, and Tinybird handles all the backfills, tables exchanges... automatically. No more `tb push datasource_v2` and copy data from `datasource_v1`.
- **Git-native deployments and CI/CD**: Every change ships through your repository. Use the built-in [CI/CD workflows](/forward/development-workflow/cicd) for automated validation, [preview deployments](/forward/core-concepts/deployments), and safe rollouts to production.
- **Local development**: Build and iterate against [Tinybird Local](/forward/core-concepts/tinybird-local) with full parity to Tinybird Cloud. Test changes on your machine before they ever reach a shared environment. And easier to verify in your CI with the local image.
- **Faster, simpler testing**: [Fixture tests](/forward/guides/test-your-project) make it easier to define realistic scenarios and catch regressions before deploy, replacing the heavier regression and data quality test workflows from Classic.
- **Cleaner project structure**: First-class [connection files](/forward/dev-reference/datafiles/connection-files), [secrets](/forward/dev-reference/commands/tb-secret), and [generic pipes](/forward/core-concepts/pipes#create-generic-pipes) replace ad-hoc include files and per-environment glue, so projects stay portable and reviewable in code.
- **Modern, consistent CLI**: A redesigned `tb` command provides a unified workflow for local development, cloud deployments, and testing, with clearer commands and better feedback.
- **AI friendly**: Use the agent skills `npx skills add tinybirdco/tinybird-agent-skills` to teach Tinybird best practices to your coding agent.
- **Active development**: New features land in Forward first. Classic continues to receive critical fixes, but the roadmap (new connectors, deployment improvements, agent integrations) is Forward-only.

## Considerations before migrating

Before migrating your workspace from Tinybird Classic, understand these key differences in Forward:

- Development is files based. You edit the .pipe, .datasource... in a Cloud Branch or locally using [Tinybird Local](/forward/core-concepts/tinybird-local). Check [Development Workflow](/forward/development-workflow) for more details.
- The following features have limitations or require changes:

{% table %}
  * Feature
  * Status
  * Solution/Alternative
  ---
  * BI Connector
  * Not supported
  * Use the [ClickHouse HTTP Interface](/forward/query-data/clickhouse-interface) instead. Most BI tools support ClickHouse HTTP connections.
  ---
  * Include files
  * Not supported
  * Use [tb secret](/forward/dev-reference/commands/tb-secret) for connector credentials and [generic pipes](/forward/core-concepts/pipes#create-generic-pipes) to reuse query logic. See [Replace include files](#replace-include-files) for migration steps.
  ---
  * CI/CD workflows
  * Different commands
  * Forward uses different CLI commands. See [CI/CD](/forward/development-workflow/cicd) for details.
  ---
  * Testing strategy
  * Different approach
  * Regression tests and data quality tests are not supported in Forward. Fixture tests have been enhanced for easier test creation and management. See [Test your project](/forward/guides/test-your-project) for details.
  ---
  * Resource-scoped tokens with `:sql_filter`
  * Not supported
  * Remove all tokens using the `:sql_filter` suffix (e.g., `DATASOURCES:READ:datasource_name:sql_filter`) before migrating. Use [JWTs](/forward/core-concepts/jwt) instead.
{% /table %}

If these changes work for your use case, continue reading to learn how to migrate.

{% callout type="caution" %}
Migration is permanent and cannot be reversed. After deploying with Forward, you cannot switch your workspace back to Classic.
{% /callout %}

## Prepare to migrate

Both migration paths start from the same setup: install the Forward CLI, authenticate, and pull your project.

{% steps %}

### Install the Tinybird Forward CLI

Run the following command to install the Tinybird Forward CLI and the Tinybird Local container:

{% snippet title="install-tinybird-forward" /%}

See [Tinybird Local](/forward/core-concepts/tinybird-local#install-tinybird) for more information.

The migration requires Forward CLI version 4.6.4 or later. Check your version with `tb --version` and run `tb update` if it's lower.

{% callout type="caution" %}
**Managing CLI Versions**: Having both Tinybird Classic and Forward CLIs installed can cause version conflicts since both use the `tb` command. To avoid these conflicts, consider:

1. Using the uv Python package manager to keep both CLIs completely isolated (recommended):

```bash
# For Classic CLI
uvx --from tinybird-cli@latest tb

# For Forward CLI
uvx --from tinybird@latest tb
```

2. Creating aliases in your shell configuration:

```bash
# Add to .bashrc or .zshrc
alias tb-classic="path/to/classic/tb"
alias tb-forward="path/to/forward/tb"
```

3. Using separate virtual environments for each CLI version.

This ensures you use the correct CLI version for each operation during migration.
{% /callout %}

The following steps use the uv Python package.

### Authenticate to your workspace

Authenticate to your workspace using the Classic CLI:

```bash
uvx --from tinybird-cli@latest tb auth --interactive
```

Follow the prompts to complete authentication.

### Pull your project

Pull your datafiles from Tinybird Cloud with the Forward CLI:

```bash
tb --cloud pull
```

For connector-backed projects, this writes a `.connection` file per connector under `connections/` and the data sources under `datasources/`, and for S3, GCS, Kafka, and DynamoDB it stores the credentials as [secrets](/forward/dev-reference/commands/tb-secret) referenced with `tb_secret(...)`. If a secret of the same name already exists, the pull reuses it and prints a warning so you can confirm the value matches before deploying.

{% /steps %}

## Migrate to Forward

`tb migrate-to-forward` completes the migration end to end. It works for projects with and without connectors (S3, GCS, Kafka, DynamoDB). If it reports changes it can't reconcile, contact [Tinybird support](mailto:support@tinybird.co).

{% steps %}

### Audit the pulled connector files

If your project doesn't use connectors, skip to the next step.

Open each pulled `.connection` file and confirm it has the connector type, credentials reference, and region. The exact fields depend on the connector:

{% tabs %}

{% tab label="S3" %}
An access-key connection references the secret key with `tb_secret(...)` and keeps the access key ID and region inline:

```text {% title="connections/s3_events.connection" %}
TYPE s3
S3_ACCESS_KEY AKIAEXAMPLE
S3_SECRET {{ tb_secret("s3_secret_s3_events") }}
S3_REGION eu-west-1
```

An IAM-role connection references the role ARN with `tb_secret(...)`:

```text {% title="connections/s3_events.connection" %}
TYPE s3
S3_ARN {{ tb_secret("s3_role_arn_s3_events") }}
S3_REGION eu-west-3
```
{% /tab %}

{% tab label="GCS" %}
A service-account connection stores the full credentials JSON as a single secret:

```text {% title="connections/gcs_events.connection" %}
TYPE gcs
GCS_SERVICE_ACCOUNT_CREDENTIALS_JSON {{ tb_secret("gcs_svc_account_creds_gcs_events") }}
```

An HMAC connection keeps the access ID inline and references the secret:

```text {% title="connections/gcs_events.connection" %}
TYPE gcs
GCS_HMAC_ACCESS_ID GOOG1EEXAMPLE
GCS_HMAC_SECRET {{ tb_secret("gcs_hmac_secret_gcs_events") }}
```
{% /tab %}

{% tab label="Kafka" %}
A Kafka connection references the credentials and any TLS material with `tb_secret(...)`. Update any [deprecated settings](/forward/ingest-data/connectors/kafka#kafka-connection-settings) flagged during the pull:

```text {% title="connections/kafka_events.connection" %}
TYPE kafka
KAFKA_BOOTSTRAP_SERVERS broker:9092
KAFKA_KEY kafka-user
KAFKA_SECRET {{ tb_secret("kafka_secret_kafka_events") }}
```
{% /tab %}

{% tab label="DynamoDB" %}
A DynamoDB connection carries the connector type, role ARN, and region:

```text {% title="connections/ddb_orders.connection" %}
TYPE dynamodb
DYNAMODB_ARN arn:aws:iam::123456789012:role/tinybird-dynamodb-role
DYNAMODB_REGION us-east-1
```
{% /tab %}

{% /tabs %}

Then open each connector-backed `.datasource` file and confirm it references the connection by name and keeps the import settings. For DynamoDB, confirm it keeps the `ReplacingMergeTree` settings that updates and deletes rely on:

```text {% title="datasources/orders.datasource" %}
ENGINE "ReplacingMergeTree"
ENGINE_SORTING_KEY "<partition_key>, <sort_key>"
ENGINE_VER "_timestamp"
ENGINE_IS_DELETED "_is_deleted"

IMPORT_CONNECTION_NAME 'ddb_orders'
IMPORT_TABLE_ARN 'arn:aws:dynamodb:us-east-1:123456789012:table/orders'
IMPORT_EXPORT_BUCKET 'my-dynamodb-export-bucket'
```

For DynamoDB, use only the S3 bucket name in `IMPORT_EXPORT_BUCKET`, not an `s3://` URI. Treat `IMPORT_TABLE_ARN` and `IMPORT_EXPORT_BUCKET` as immutable: the first Forward deployment should preserve the existing DynamoDB binding, not change it.

### Run the migration

Run the migration command:

```bash
tb migrate-to-forward
```

This command deletes branches and releases, runs a deploy check, generates a `tinybird.config.json` file, switches the workspace to Forward, and deploys it. After it finishes, query a few endpoints and confirm ingestion continues.

If you have CI/CD configured, push the changes to your repository to complete the migration. See [CI/CD](/forward/development-workflow/cicd) for details on the CI workflow, CD workflow, and creating preview deployments.

{% callout type="info" %}
If your workspace uses AWS PrivateLink for private networking, the migration doesn't change it. Private networking is configured at the workspace and region level, not in the datafiles you migrate, and the workspace keeps the same region. Connectors reach AWS through the same IAM role and endpoints before and after migration.
{% /callout %}

{% /steps %}

The migration is complete! Your project will continue working as expected; you do not need to change your tokens, endpoint URLs, or anything else.

## Common migration errors

Common errors and changes include (but are not limited to):

### Replace include files

Include files are not supported in Forward. The fix depends on your use of include files:

- If you use include files to store secrets, use [tb secret](/forward/dev-reference/commands/tb-secret) to set secrets in your local and cloud environments.
- If you use include files to reuse query logic, you can create [generic pipes](/forward/core-concepts/pipes#create-generic-pipes) and reference them in your endpoint pipes. For example:

```tinybird {% title="reusable_filters.pipe" %}
NODE apply_params
SQL >
    %
    SELECT * FROM my_datasource
    WHERE
        tenant_id = {{ String(tenant) }}
        AND date BETWEEN {{ Date(start_date) }} AND {{ Date(end_date) }}
```

```tinybird {% title="my_endpoint.pipe" %}
NODE endpoint
SQL >
    %
    SELECT * FROM reusable_filters

TYPE endpoint
```

## Next steps

* Learn about working with Forward in the [Forward documentation](/forward).
