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 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_v2and copy data fromdatasource_v1. - Git-native deployments and CI/CD: Every change ships through your repository. Use the built-in CI/CD workflows for automated validation, preview deployments, and safe rollouts to production.
- Local development: Build and iterate against 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 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, secrets, and generic pipes replace ad-hoc include files and per-environment glue, so projects stay portable and reviewable in code.
- Modern, consistent CLI: A redesigned
tbcommand 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-skillsto 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. Check Development Workflow for more details.
- The following features have limitations or require changes:
| Feature | Status | Solution/Alternative |
|---|---|---|
| BI Connector | Not supported | Use the ClickHouse HTTP Interface instead. Most BI tools support ClickHouse HTTP connections. |
| Include files | Not supported | Use tb secret for connector credentials and generic pipes to reuse query logic. See Replace include files for migration steps. |
| CI/CD workflows | Different commands | Forward uses different CLI commands. See CI/CD 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 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 instead. |
If these changes work for your use case, continue reading to learn how to migrate.
Migration is permanent and cannot be reversed. After deploying with Forward, you cannot switch your workspace back to Classic.
Prepare to migrate¶
Both migration paths start from the same setup: install the Forward CLI, authenticate, and pull your project.
Install the Tinybird Forward CLI¶
Run the following command to install the Tinybird Forward CLI and the Tinybird Local container:
curl https://tinybird.co | sh
See Tinybird Local 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.
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:
- Using the uv Python package manager to keep both CLIs completely isolated (recommended):
# For Classic CLI
uvx --from tinybird-cli@latest tb
# For Forward CLI
uvx --from tinybird@latest tb
- Creating aliases in your shell configuration:
# Add to .bashrc or .zshrc
alias tb-classic="path/to/classic/tb"
alias tb-forward="path/to/forward/tb"
- Using separate virtual environments for each CLI version.
This ensures you use the correct CLI version for each operation during migration.
The following steps use the uv Python package.
Authenticate to your workspace¶
Authenticate to your workspace using the Classic CLI:
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:
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 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.
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.
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:
An access-key connection references the secret key with tb_secret(...) and keeps the access key ID and region inline:
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(...):
TYPE s3
S3_ARN {{ tb_secret("s3_role_arn_s3_events") }}
S3_REGION eu-west-3
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:
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:
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 for details on the CI workflow, CD workflow, and creating preview deployments.
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.
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 to set secrets in your local and cloud environments.
- If you use include files to reuse query logic, you can create generic pipes and reference them in your endpoint pipes. For example:
NODE apply_params
SQL >
%
SELECT * FROM my_datasource
WHERE
tenant_id = {{ String(tenant) }}
AND date BETWEEN {{ Date(start_date) }} AND {{ Date(end_date) }}
NODE endpoint
SQL >
%
SELECT * FROM reusable_filters
TYPE endpoint
Next steps¶
- Learn about working with Forward in the Forward documentation.