FerrFlow treats a repository as a monorepo when the config defines more than one package. Each package is versioned independently based on its own git history.

Package isolation

FerrFlow uses path prefixes to determine which commits belong to which package. Only commits that touch files under path (or sharedPaths) trigger a release for that package.

JSON

{
  "package": [
    {
      "name": "api",
      "path": "packages/api"
    },
    {
      "name": "site",
      "path": "packages/site"
    }
  ]
}

TOML

[[package]]
name = "api"
path = "packages/api"

[[package]] name = "site" path = "packages/site"

JSON5

{
  package: [
    {
      name: "api",
      path: "packages/api",
    },
    {
      name: "site",
      path: "packages/site",
    },
  ],
}

YAML

package:
  - name: api
    path: packages/api
  - name: site
    path: packages/site

Shared dependencies

If you have code shared between packages (e.g., a packages/shared/ library), declare it as a sharedPaths entry. A change to any shared path triggers a release for every package that lists it:

JSON

{
  "package": [
    {
      "name": "api",
      "path": "packages/api",
      "sharedPaths": ["packages/shared/"]
    },
    {
      "name": "site",
      "path": "packages/site",
      "sharedPaths": ["packages/shared/"]
    }
  ]
}

TOML

[[package]]
name = "api"
path = "packages/api"
shared_paths = ["packages/shared/"]

[[package]] name = "site" path = "packages/site" shared_paths = ["packages/shared/"]

JSON5

{
  package: [
    {
      name: "api",
      path: "packages/api",
      sharedPaths: ["packages/shared/"],
    },
    {
      name: "site",
      path: "packages/site",
      sharedPaths: ["packages/shared/"],
    },
  ],
}

YAML

package:
  - name: api
    path: packages/api
    sharedPaths:
      - packages/shared/
  - name: site
    path: packages/site
    sharedPaths:
      - packages/shared/

Package dependencies

Use dependsOn to declare that a package depends on another. When a dependency is released, the dependent package automatically receives a patch bump — even if none of its own files changed. This cascades transitively: if app depends on cli and cli depends on core, bumping core bumps both cli and app.

JSON

{
  "package": [
    {
      "name": "core",
      "path": "packages/core"
    },
    {
      "name": "cli",
      "path": "packages/cli",
      "dependsOn": ["core"]
    },
    {
      "name": "app",
      "path": "packages/app",
      "dependsOn": ["cli"]
    }
  ]
}

TOML

[[package]]
name = "core"
path = "packages/core"

[[package]] name = "cli" path = "packages/cli" depends_on = ["core"]

[[package]] name = "app" path = "packages/app" depends_on = ["cli"]

JSON5

{
  package: [
    {
      name: "core",
      path: "packages/core",
    },
    {
      name: "cli",
      path: "packages/cli",
      dependsOn: ["core"],
    },
    {
      name: "app",
      path: "packages/app",
      dependsOn: ["cli"],
    },
  ],
}

YAML

package:
  - name: core
    path: packages/core
  - name: cli
    path: packages/cli
    dependsOn:
      - core
  - name: app
    path: packages/app
    dependsOn:
      - cli

Git tag format

By default, monorepo tags use the {name}@v{version} format:

api@v1.2.0
site@v0.4.1

Configure this with the tagTemplate field:

JSON

{
  "workspace": {
    "tagTemplate": "{name}@v{version}"
  }
}

TOML

[workspace]
tag_template = "{name}@v{version}"

JSON5

{
  workspace: {
    tagTemplate: "{name}@v{version}",
  },
}

YAML

workspace:
  tagTemplate: "{name}@v{version}"

For a single-package repo, the default is v{version} (no name prefix).

FerrFlow looks for the most recent tag matching the template to determine what commits are new.

Independent cadences

Packages release independently. In a single ferrflow release run:

  • api may bump from 1.2.01.3.0 (new feat: commit)
  • site may bump from 0.4.00.4.1 (only fix: commits)
  • shared may not release at all (only chore: commits)

Per-package overrides

Each package can override the workspace-level versioning strategy and tagTemplate:

JSON

{
  "workspace": {
    "versioning": "semver",
    "tagTemplate": "{name}@v{version}"
  },
  "package": [
    {
      "name": "api",
      "path": "packages/api",
      "versioning": "calver"
    },
    {
      "name": "site",
      "path": "packages/site",
      "tagTemplate": "site-v{version}"
    }
  ]
}

TOML

[workspace]
versioning = "semver"
tag_template = "{name}@v{version}"

[[package]] name = "api" path = "packages/api" versioning = "calver"

[[package]] name = "site" path = "packages/site" tag_template = "site-v{version}"

JSON5

{
  workspace: {
    versioning: "semver",
    tagTemplate: "{name}@v{version}",
  },
  package: [
    {
      name: "api",
      path: "packages/api",
      versioning: "calver",
    },
    {
      name: "site",
      path: "packages/site",
      tagTemplate: "site-v{version}",
    },
  ],
}

YAML

workspace:
  versioning: semver
  tagTemplate: "{name}@v{version}"

package:

  • name: api path: packages/api versioning: calver
  • name: site path: packages/site tagTemplate: "site-v{version}"