---
title: After migrating from Classic
meta:
  description: What changed in your Workspace after migrating to Forward.
---

# After migrating from Classic

If Tinybird migrated your Workspace for you, it was upgraded in place and kept its name. Your data, Tokens, and Endpoint URLs are unchanged. What changes is how you make changes from now on.

This guide covers what's different in your migrated Workspace and how to work with Forward from this point onwards. For why Forward works this way, see [Why migrate to Forward](/forward/guides/migrate-from-classic#why-migrate-to-forward).

## What didn't change

The migration moved no data and rewrote no URLs. The following survived it untouched:

- **Your data.** Every Data Source you had, with every row still in it. The migration upgraded the Workspace around your data rather than copying, moving, or reingesting it, so there's nothing to restore or backfill.
- **Your Tokens.** Same values and same permissions. Nothing to rotate.
- **Your Endpoint URLs.** `/v0/pipes/<pipe>.json` answers as it did before, with the same Query Parameters and the same response formats.
- **Your ingestion.** The [Events API](/forward/ingest-data/events-api) and the Data Sources API append operations are unchanged. Producers kept writing during the migration.
- **Your Copy Pipes.** Still running on the same schedule.

If your application talks to Tinybird over HTTP, it kept working through the migration and you don't need to change anything in it.

## What changed

### Changes go through deployments

Your Data Sources, Pipes, and Connections are now described by [datafiles](/forward/dev-reference/datafiles): a project you keep in version control and deploy. **The Tinybird UI shows you what's running. It's no longer where you change it.**

The Classic management endpoints now return a 403:

```text
Adding or modifying data sources to this workspace can only be done via deployments.
```

You get the same response for Pipes, for Connections, and for the Classic CLI commands that wrapped them. Reading and querying aren't affected.

### Your Classic Branches and releases were deleted

The migration deletes your Classic Branches and releases. It doesn't carry them over, and you can't recover them. Each has an equivalent in Forward:

- **Branches.** Forward has its own [Cloud Branches](/forward/core-concepts/branches), and they're the default way to develop a project. A branch gets its own database, Token namespace, and API surface, and can attach the latest production partition so you develop against real values. Create one with `tb branch create`, or run `tb build` from a Git branch and Tinybird creates a matching Cloud Branch for you.
- **Releases.** [Deployments](/forward/core-concepts/deployments) replace them. You prepare each change as a new deployment, check and test it, then promote it. To roll back, promote the previous deployment.

### Read and append Token scopes live in your datafiles

Your Tokens keep working and keep their values, but the resource scopes `DATASOURCES:READ`, `DATASOURCES:APPEND`, and `PIPES:READ` are now granted by the datafile that defines the resource:

```tinybird {% title="datasources/events.datasource" %}
TOKEN "tracker" APPEND
```

Granting those scopes through the Tokens API returns the same 403 as above. Admin Tokens aren't affected, so you can still create and revoke them as before. See [Tokens](/forward/core-concepts/tokens).

### The CLI is a different tool

`tb` is now the Tinybird Forward CLI. It runs a complete Tinybird on your machine, builds and tests your project locally before anything reaches Tinybird Cloud, and deploys it when you're ready. Classic CLI commands don't carry over. See [Where your old workflow went](#where-your-old-workflow-went).

The CLI isn't the only way to work with Forward. See [How you work with Forward from here](#how-you-work-with-forward-from-here).

## Get your project onto your machine

Your Workspace runs in Forward, but the datafiles that describe it aren't on your machine yet. This is the one piece of setup the migration couldn't do for you.

{% 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.

### Log in to your Workspace

```shell
tb login --workspace <your-workspace>
```

A browser window opens to confirm. If your Workspace isn't in the default region, run `tb login -i` and select your region from the list. See [Regions and endpoints](https://docs.tinybird.co/api-reference#regions-and-endpoints).

### Pull your project

```shell
mkdir my-tinybird-project && cd my-tinybird-project
tb --cloud pull
```

This writes everything your Workspace runs as datafiles, in the layout Forward expects: `datasources/`, `endpoints/`, `pipes/`, `materializations/`, `copies/`, and `connections/`.

For connector-backed projects, the pull writes a `.connection` file per Connection and stores the credentials as [secrets](/forward/dev-reference/commands/tb-secret) referenced with `tb_secret(...)`. Open each `.connection` file and confirm the credentials reference and region before you deploy.

### Commit your project

```shell
git init && git add . && git commit -m "Tinybird project"
```

From now on, this repository is the source of truth for your Workspace. Keep it wherever the rest of your code lives.

### Check that it builds

```shell
tb dev
```

`tb dev` starts [Tinybird Local](/forward/core-concepts/tinybird-local) and rebuilds as you edit, so you can develop against real queries without touching production. `tb build` runs a single build, and `tb test` runs your [tests](/forward/guides/test-your-project).

{% /steps %}

## Make your first change

The loop from now on is the same every time, whether you're adding a column or a whole Endpoint:

```shell
tb build
tb test
tb --cloud deploy
```

`tb --cloud deploy` creates a deployment, checks it against your live Workspace, and promotes it when it's ready.

{% callout type="caution" %}
If a change would drop or rewrite existing data, the deploy stops and tells you. Pass `--allow-destructive-operations` only when that's what you intend. See [Evolve data sources](/forward/guides/evolve-data-source).
{% /callout %}

## How you work with Forward from here

`tb migrate-to-forward` writes `project_type: "cli"` into your `tinybird.config.json`, so your migrated project defines its resources as datafiles. That's the closest continuation of how you worked in Classic, and everything above assumes it. It isn't the only option:

- **Datafiles and the Tinybird CLI.** What you have now. Resources live in `.datasource`, `.pipe`, and `.connection` files, and `tb` builds, tests, and deploys them. See the [CLI quickstart](/forward/quickstarts/cli).
- **TypeScript or Python SDK.** Define the same resources in code and use a typed client for ingest and queries. You don't rewrite them by hand: the SDKs convert your existing datafiles for you. See [Work with the TypeScript or Python SDK](#work-with-the-typescript-or-python-sdk).
- **Coding agents.** Install the Tinybird agent skills so an agent understands your project structure and workflow:

```shell
npx skills add tinybirdco/tinybird-agent-skills
```

See [Agent skills](/forward/development-workflow/agent-skills).

## Work with the TypeScript or Python SDK

If you'd rather define your project in TypeScript or Python than in datafiles, each SDK ships its own `tinybird` CLI that can convert what you already have. The result is the same Workspace and the same deployments, described in code.

{% steps %}

### Install the SDK

{% tabs initial="TypeScript SDK" %}

{% tab label="TypeScript SDK" %}

```shell
pnpm add @tinybirdco/sdk
```

{% /tab %}

{% tab label="Python SDK" %}

```shell
pip install tinybird-sdk
```

Supported Python versions are 3.11, 3.12, and 3.13.

{% /tab %}

{% /tabs %}

### Initialize the project

{% tabs initial="TypeScript SDK" %}

{% tab label="TypeScript SDK" %}

```shell
npx tinybird init
```

This creates `tinybird.config.json`, `lib/tinybird.ts` for your resource and client definitions, and `.env.local` for authentication. It also authenticates you against Tinybird Cloud and can add CI/CD workflow files.

{% /tab %}

{% tab label="Python SDK" %}

```shell
tinybird init
```

This creates the project config, a module for your resource definitions, and `.env.local` for authentication. It also authenticates you against Tinybird Cloud and can add CI/CD workflow files.

{% /tab %}

{% /tabs %}

### Pull your Workspace resources

{% tabs initial="TypeScript SDK" %}

{% tab label="TypeScript SDK" %}

```shell
npx tinybird pull
```

{% /tab %}

{% tab label="Python SDK" %}

```shell
tinybird pull
```

{% /tab %}

{% /tabs %}

This downloads what your Workspace runs as datafiles. If you already ran `tb --cloud pull`, you can point the next step at those files instead.

### Convert the datafiles into code

Pass the datafiles you want to convert. Run it with `--dry-run` first to see what it produces:

{% tabs initial="TypeScript SDK" %}

{% tab label="TypeScript SDK" %}

```shell
npx tinybird migrate "tinybird/**/*.datasource" "tinybird/**/*.pipe" "tinybird/**/*.connection"
```

{% /tab %}

{% tab label="Python SDK" %}

```shell
tinybird migrate "tinybird/**/*.datasource" "tinybird/**/*.pipe" "tinybird/**/*.connection"
```

The Python SDK also has `tinybird generate`, which writes datafiles back out from your Python definitions.

{% /tab %}

{% /tabs %}

Review the generated definitions against your datafiles before you deploy.

### Develop and deploy

{% tabs initial="TypeScript SDK" %}

{% tab label="TypeScript SDK" %}

```shell
npx tinybird dev
npx tinybird deploy --check
npx tinybird deploy
```

`npx tinybird dev` watches for changes and syncs them to a [Cloud Branch](/forward/core-concepts/branches) by default. Pass `--local` to work against [Tinybird Local](/forward/core-concepts/tinybird-local) instead, or `--branch` to name the branch.

{% /tab %}

{% tab label="Python SDK" %}

```shell
tinybird dev
tinybird deploy --check
tinybird deploy
```

`tinybird dev` builds server side and watches for changes. Use `--with-connections` when you want connector ingestion running while you develop.

{% /tab %}

{% /tabs %}

`tinybird deploy` targets your main Workspace, and takes `--allow-destructive-operations` for the same cases as the CLI.

{% /steps %}

For the full command list, see the [TypeScript SDK CLI](/forward/dev-reference/commands/typescript-sdk-cli) and [Python SDK CLI](/forward/dev-reference/commands/python-sdk-cli) references. For the resource definitions themselves, see [TypeScript SDK resources](/forward/dev-reference/typescript-sdk-resources) and [Python SDK resources](/forward/dev-reference/python-sdk-resources).

## Where to look when something breaks

Forward gives you the same logs in the UI and the CLI. To follow an ingestion issue, a job, or a failing Endpoint from your terminal:

```shell
tb --cloud logs
```

By default this reads `tinybird.datasources_ops_log`, `tinybird.pipe_stats_rt`, and `tinybird.jobs_log` for the last hour. Use `--source` to target others, such as `tinybird.endpoint_errors` or `tinybird.kafka_ops_log`, and `--start` to widen the window.

The **Logs** page in Tinybird Cloud shows the same events. For longer investigations, query the [Service Data Sources](/forward/monitoring/service-datasources) directly, starting with the [query log](/forward/monitoring/query-log) for Endpoint and query behavior.

## Where your old workflow went

{% table %}
  * In Classic
  * In Forward
  ---
  * Editing a Pipe or Data Source in the UI
  * Edit the datafile, then run `tb --cloud deploy`
  ---
  * `tb push` and `tb pull`
  * `tb --cloud deploy` and `tb --cloud pull`
  ---
  * `POST /v0/datasources` and `POST /v0/pipes`
  * Datafiles, applied by a deployment
  ---
  * Classic Branches
  * [Cloud Branches](/forward/core-concepts/branches), created with `tb branch create` or automatically by `tb build`
  ---
  * Releases
  * [Deployments](/forward/core-concepts/deployments)
  ---
  * `tb auth`
  * `tb login`
  ---
  * Regression and data quality tests
  * Fixture tests run by `tb test`. See [Test your project](/forward/guides/test-your-project)
{% /table %}

## Troubleshooting

### 403: modifications can only be done via deployments

Something is still trying to change resources through the Classic API or the Classic CLI, often a deploy script or a continuous integration job. Point it at a deployment instead, following the steps in [Get your project onto your machine](#get-your-project-onto-your-machine). See [CI/CD](/forward/development-workflow/cicd).

### tb migrate-to-forward reports that it's unavailable

Your Workspace is already migrated, so there's nothing left to run:

```text
This command is unavailable for Tinybird Forward workspaces.
```

### A Classic Branch or release is missing

The migration deleted them and they can't be recovered. Recreate the Branch as a [Cloud Branch](/forward/core-concepts/branches) from your pulled project:

```shell
tb branch create <branch-name> --last-partition
```

For a release, promote the equivalent [deployment](/forward/core-concepts/deployments) instead.

### An Endpoint returns a different result than before

The migration doesn't change queries or data, so this isn't expected. Contact [Tinybird support](/forward/support) with your Workspace name before you change anything yourself.

## See also

- [Forward documentation](/forward)
- [Datafiles](/forward/dev-reference/datafiles)
- [Deployments](/forward/core-concepts/deployments)
- [Tokens](/forward/core-concepts/tokens)
- [CI/CD](/forward/development-workflow/cicd)
- [Test your project](/forward/guides/test-your-project)
- [Tinybird Local](/forward/core-concepts/tinybird-local)
- [TypeScript SDK](/forward/quickstarts/typescript-sdk) and [Python SDK](/forward/quickstarts/python-sdk)
- [Agent skills](/forward/development-workflow/agent-skills)
- [Service Data Sources](/forward/monitoring/service-datasources)
