# How to Migrate from Rudder CLI Spec v0.1 to v1


> Migrate your Rudder CLI project from spec format v0.1 to v1 with an automated command.



This migration guide helps you migrate your Rudder CLI project from spec version 0.1 to v1.

## Overview

`rudder/v1` is a comprehensive redesign of the original `rudder/v0.1` spec format. It improves consistency across resource kinds, replaces ambiguous field names, adopts snake case conventions, and moves to compact URN-style references throughout.

When you run the `migrate` command, Rudder CLI automatically rewrites the spec files present in the specified location and applies changes related to:

- Spec version upgrades
- Rename resource kinds
- Using compact URN references
- Updating property and custom type definitions
- Updating Tracking Plan rules
- Updating variant definitions
- Updating import metadata
- Updating event stream source references

**Warning:** As the migration process rewrites the spec files in place, RudderStack recommends committing or backing up your project before running the `migrate` command.

## Run the migration

To migrate your project automatically, run the following command:

```bash
rudder-cli migrate --location <path-to-project>
```

## Breaking changes

The following sections list the breaking changes introduced in the spec format upgrade from v0.1 to v1.

**Info**

The `migrate` command automatically handles these changes, with one exception: Tracking Plan `includes` rules, which you must inline yourself.

See [Remove Tracking Plan includes](#remove-tracking-plan-includes) for more information.

### Update the version field

The field-name, convention, and reference changes in `rudder/v1` break the existing spec contract. The version is bumped to signal the new contract, so tooling and validation can distinguish it from legacy spec version `rudder/v0.1`.

#### v1

```yaml
version: rudder/v1
```
#### v0.1

```yaml
version: rudder/0.1
# or
version: rudder/v0.1
```

### Rename the Tracking Plan kind

The Tracking Plan kind changes from `tp` to `tracking-plan`. The abbreviated `tp` was an opaque abbreviation, while `tracking-plan` is self-documenting and consistent with how the resource is named everywhere else.

#### v1

```yaml
version: rudder/v1
kind: tracking-plan
```
#### v0.1

```yaml
version: rudder/v0.1
kind: tp
```

### Compact URN references

All cross-resource references change from the path-based format (`#/<kind>/<group>/<id>`) to the compact URN format (`#<resource-type>:<id>`). Path-based references were verbose and order-dependent, while compact URNs are shorter and encode the resource type, making references unambiguous and easier to read.

The following table lists the updated reference format for each resource type:

| Resource | v0.1 | v1 |
|----------|------|-----|
| Property | `#/properties/group/prop_id` | `#property:prop_id` |
| Event | `#/events/group/event_id` | `#event:event_id` |
| Category | `#/categories/group/cat_id` | `#category:cat_id` |
| Custom type | `#/custom-types/group/type_id` | `#custom-type:type_id` |
| Tracking plan | `#/tp/group/tp_id` | `#tracking-plan:tp_id` |

The following example shows an event referencing a category:

#### v1

```yaml
version: rudder/v1
kind: events
spec:
  events:
    - id: api_tracking
      name: API Tracking
      event_type: track
      category: "#category:user_actions"
```
#### v0.1

```yaml
version: rudder/v0.1
kind: events
spec:
  events:
    - id: api_tracking
      name: API Tracking
      event_type: track
      category: "#/categories/app_categories/user_actions"
```

### Updated property definitions

Property definitions undergo four changes: 

- `propConfig` is renamed to `config` for brevity and consistency with other resource field naming
- `config` keys move to snake case to align with YAML ecosystem conventions
- `type` becomes `types` (an array) to eliminate fragile comma-separated string parsing
- Array item types are hoisted to top-level to reduce nesting and make type information more discoverable

#### `propConfig` renamed to `config`

#### v1

```yaml
config:
  enum: ["GET", "PUT", "POST"]
```
#### v0.1

```yaml
propConfig:
  enum: ["GET", "PUT", "POST"]
```

#### `config` keys converted to snake case

#### v1

```yaml
config:
  minimum: 0
  maximum: 10
  multiple_of: 2
  min_length: 10
  max_length: 64
```
#### v0.1

```yaml
propConfig:
  minimum: 0
  maximum: 10
  multipleOf: 2
  minLength: 10
  maxLength: 64
```

#### Multi-type `type` string replaced by `types` array

Properties with multiple types use a `types` array instead of a comma-separated `type` string.

#### v1

```yaml
- id: status_code
  types:
    - integer
    - "null"
```
#### v0.1

```yaml
- id: status_code
  type: "integer,null"
```

#### Array item types hoisted to top-level

#### v1

```yaml
- id: tag_list
  type: array
  item_type: string

# Multiple item types
- id: user_scores
  type: array
  item_types:
    - integer
    - number
```
#### v0.1

```yaml
- id: tag_list
  type: array
  propConfig:
    itemTypes:
      - string
```

### Full property definition example

#### v1

```yaml
version: rudder/v1
kind: properties
metadata:
  name: api_tracking
spec:
  properties:
    - id: api_method
      name: API Method
      type: string
      description: "http method of the api called"
      config:
        enum: ["GET", "PUT", "POST", "DELETE", "PATCH"]
    - id: http_retry_count
      name: HTTP Retry Count
      type: integer
      description: "Number of times to retry the API call"
      config:
        minimum: 0
        maximum: 10
        multiple_of: 2
    - id: password
      name: Password
      type: string
      config:
        min_length: 10
        max_length: 64
```
#### v0.1

```yaml
version: rudder/v0.1
kind: properties
metadata:
  name: api_tracking
spec:
  properties:
    - id: api_method
      name: API Method
      type: string
      description: "http method of the api called"
      propConfig:
        enum: ["GET", "PUT", "POST", "DELETE", "PATCH"]
    - id: http_retry_count
      name: HTTP Retry Count
      type: integer
      description: "Number of times to retry the API call"
      propConfig:
        minimum: 0
        maximum: 10
        multipleOf: 2
    - id: password
      name: Password
      type: string
      propConfig:
        minLength: 10
        maxLength: 64
```

### Custom type definitions

Custom type definitions undergo two changes: 

- `$ref` (a JSON Schema artifact with no semantic meaning in this context) is replaced by the clearer `property`
- `config` keys follow the same snake case convention as properties

#### `$ref` replaced by `property` in type properties

#### v1

```yaml
spec:
  types:
    - id: login
      type: object
      properties:
        - property: "#property:username"
          required: true
```
#### v0.1

```yaml
spec:
  types:
    - id: login
      type: object
      properties:
        - $ref: "#/properties/api_tracking/username"
          required: true
```

#### Config keys converted from camel to snake case {#custom-type-config-keys}

#### v1

```yaml
config:
  min_length: 10
  max_length: 255
```
#### v0.1

```yaml
config:
  minLength: 10
  maxLength: 255
```

### Tracking Plan rules

Tracking Plan rules undergo two structural changes: 

- The `event` object wrapper was redundant, so `event` now holds a direct reference string consistent with how other references are expressed. 
- `allow_unplanned` is renamed to `additional_properties` and moved to rule level for clarity.
- `$ref` is replaced by `property` in rule properties, using compact URNs

#### Remove Tracking Plan includes

The experimental `includes` feature available for `rudder/v0.1` Tracking Plans is not supported in `rudder/v1`.

Note that:

- The `migrate` command does not convert `includes` rules — it copies them across unchanged.
- If a migrated Tracking Plan still contains an `includes` rule, validation fails on the rule's missing `event` field at `/rules/<n>/event`:

```text
error[datacatalog/tracking-plans/spec-syntax-valid]: 'event' is required
```

Before running `migrate`, replace each `includes` rule with the event rules it references. Define those rules directly in the `rules` list of the `rudder/v0.1` Tracking Plan, then run `migrate` to convert them to `rudder/v1` along with the rest of the project.

#### The `event` object replaced with a direct reference string

The `event` field changes from an object (containing `$ref`, `allow_unplanned`, and `identity_section`) to a direct reference string. The `allow_unplanned` and `identity_section` fields move to rule level:

- `event.$ref` becomes `event` (direct string)
- `event.allow_unplanned` becomes `additional_properties` (moved to rule level and renamed)
- `event.identity_section` becomes `identity_section` (moved to rule level)

#### v1

```yaml
rules:
  - type: event_rule
    id: login
    event: "#event:api_tracking"
    additional_properties: false
    identity_section: properties
```
#### v0.1

```yaml
rules:
  - type: event_rule
    id: login
    event:
      $ref: "#/events/api_tracking/api_tracking"
      allow_unplanned: false
      identity_section: properties
```

#### `$ref` replaced by `property` in rule properties

#### v1

```yaml
properties:
  - property: "#property:username"
    required: true
  - property: "#property:password"
    required: true
```
#### v0.1

```yaml
properties:
  - $ref: "#/properties/api_tracking/username"
    required: true
  - $ref: "#/properties/api_tracking/password"
    required: true
```

### Full Tracking Plan example

#### v1

```yaml
version: rudder/v1
kind: tracking-plan
metadata:
  name: api_tracking
spec:
  id: api_tracking
  display_name: API Tracking
  rules:
    - type: event_rule
      id: login
      event: "#event:api_tracking"
      additional_properties: false
      properties:
        - property: "#property:username"
          required: true
        - property: "#property:password"
          required: true
```
#### v0.1

```yaml
version: rudder/v0.1
kind: tp
metadata:
  name: api_tracking
spec:
  id: api_tracking
  display_name: API Tracking
  rules:
    - type: event_rule
      id: login
      event:
        $ref: "#/events/api_tracking/api_tracking"
        allow_unplanned: false
      properties:
        - $ref: "#/properties/api_tracking/username"
          required: true
        - $ref: "#/properties/api_tracking/password"
          required: true
```

### Variant definitions

Variants appear in both custom types and Tracking Plan rules — they undergo the following changes:

- The variant `default` is restructured to remove an array-of-objects pattern in favor of an explicit `properties` wrapper that matches the shape used in rules
- All `$ref` fields within variant discriminators and cases are replaced by `property` with compact URN references

#### Variant `default` restructured from array to object

#### v1

```yaml
variants:
  - type: discriminator
    default:
      properties:
        - property: "#property:prop_a"
          required: true
```
#### v0.1

```yaml
variants:
  - type: discriminator
    default:
      - $ref: "#/properties/group/prop_a"
        required: true
```

#### Variant discriminator and case properties

Variant discriminator and case properties follow the same `$ref` to `property` change.

#### v1

```yaml
variants:
  - type: discriminator
    discriminator: "#property:api_method"
    cases:
      - display_name: "Create Entity"
        match: ["POST"]
        properties:
          - property: "#property:user_agent"
            required: true
```
#### v0.1

```yaml
variants:
  - type: discriminator
    discriminator: "#/properties/api_tracking/api_method"
    cases:
      - display_name: "Create Entity"
        match: ["POST"]
        properties:
          - $ref: "#/properties/api_tracking/user_agent"
            required: true
```

### Import metadata

The `local_id` field in import metadata is replaced by a `urn` field that includes the resource type. The `urn` field encodes the resource type alongside the local ID, eliminating ambiguity when multiple resource types share the same ID values.

The URN format is `<resource-type>:<local-id>`. 

Valid resource types include:

- `property`
- `event`
- `category`
- `custom-type`
- `tracking-plan`
- `event-stream-source`
- `retl-source-sql-model`

#### v1

```yaml
metadata:
  name: test_props
  import:
    workspaces:
      - workspace_id: ws-123
        resources:
          - urn: property:prop1
            remote_id: remote-prop-1
```
#### v0.1

```yaml
metadata:
  name: test_props
  import:
    workspaces:
      - workspace_id: ws-123
        resources:
          - local_id: prop1
            remote_id: remote-prop-1
```

### Event stream source references

The Tracking Plan reference in event stream source governance uses the compact URN format, consistent with the unified compact URN format adopted for all cross-resource references in v1.

#### v1

```yaml
version: rudder/v1
kind: event-stream-source
spec:
  id: test-source
  name: Test Source
  type: javascript
  governance:
    validations:
      tracking_plan: "#tracking-plan:tp-abc123"
```
#### v0.1

```yaml
version: rudder/v0.1
kind: event-stream-source
spec:
  id: test-source
  name: Test Source
  type: javascript
  governance:
    validations:
      tracking_plan: "#/tp/group/tp-abc123"
```

<br />

