# Catalog Protocol (/docs/catalog)



The `catalog:` protocol lets a workspace define dependency versions once and reference them from every `package.json`. Updates land in one place and propagate to every consumer.

Where catalogs live [#where-catalogs-live]

Catalogs can be declared in two files:

* **`snpm-workspace.yaml`** — declare a default catalog and named catalogs inline:

  ```yaml
  packages:
    - packages/*

  catalog:
    react: ^18.2.0
    typescript: ^5.4.0

  catalogs:
    build:
      vite: ^5.0.0
    testing:
      vitest: ^1.0.0
  ```

* **`snpm-catalog.yaml`** — standalone catalog file at the workspace root:

  ```yaml title="snpm-catalog.yaml"
  catalog:
    react: ^18.2.0

  catalogs:
    build:
      vite: ^5.0.0
  ```

If both files define a key, `snpm-workspace.yaml` wins.

`pnpm-workspace.yaml` is also recognized and its `catalog` / `catalogs` blocks are merged in for compatibility.

Using catalog versions [#using-catalog-versions]

Reference catalog entries from any `package.json` in the workspace:

```json title="apps/web/package.json"
{
  "dependencies": {
    "react": "catalog:",
    "react-dom": "catalog:"
  },
  "devDependencies": {
    "vite": "catalog:build",
    "vitest": "catalog:testing"
  }
}
```

| Syntax           | Meaning                                                  |
| ---------------- | -------------------------------------------------------- |
| `catalog:`       | Resolve from the default catalog (`catalog:` block)      |
| `catalog:<name>` | Resolve from the named catalog (`catalogs.<name>` block) |

Range syntax [#range-syntax]

Catalog values are normal npm semver ranges:

```yaml
catalog:
  # caret
  react: ^18.2.0

  # exact
  lodash: 4.17.21

  # explicit range
  typescript: ">=5.0.0 <6.0.0"

  # pre-release tag
  next: "latest"
```

Updating a version [#updating-a-version]

1. Edit `snpm-workspace.yaml` (or `snpm-catalog.yaml`).
2. Run `snpm install` from the workspace root.

Every package that references the catalog entry picks up the new version on the next install.

Mixing with overrides [#mixing-with-overrides]

Catalogs control direct dependency versions. To force versions on **transitive** dependencies, use `snpm-overrides.yaml` or `package.json` `snpm.overrides` / `pnpm.overrides` — see [Configuration](/docs/configuration#overrides-configuration).

Best practices [#best-practices]

* **Group catalogs by purpose** — `build`, `testing`, `linting`. Default catalog for framework-level deps.
* **Pin sharp boundaries with exact versions** for tools that have known regressions, and use carets for libraries you want to track within the major.
* **Combine with `snpm-switch`** by pinning the `snpm` version in the root `package.json`, so the catalog rules apply to the same `snpm` build everywhere.
* **Use comments freely** — both `snpm-workspace.yaml` and `snpm-catalog.yaml` are YAML, so contributors can read why a version is pinned.
