# Versioning Strategies for Cordis: A Three-Layer Approach in the Monorepo

> Discover Cordis versioning strategies: a three-layer approach for monorepos. Learn about root, package, and runtime loader versions to manage your project effectively.

- Repository: [Cordiverse/cordis](https://github.com/cordiverse/cordis)
- Tags: best-practices
- Published: 2026-09-13

---

**Cordis employs a three-tier versioning strategy that isolates the monorepo root at `0.0.0`, maintains independent semantic versions for each package, and exposes runtime loader versions (`v1` or `v2`) based on Node.js feature detection.**

Cordis adopts a sophisticated, layered versioning approach designed to maximize flexibility across its monorepo architecture. Understanding these **versioning strategies for Cordis** is essential for plugin authors and contributors who need to navigate the repository's release cadence and runtime compatibility guarantees. The system separates concerns between workspace management, package distribution, and runtime capability detection.

## The Three Layers of Versioning in Cordis

### Monorepo Root: The 0.0.0 Placeholder

The root [`package.json`](https://github.com/cordiverse/cordis/blob/main/package.json) of the Cordis repository is intentionally fixed at version `"0.0.0"`. This serves as a workspace marker for Yarn or PNPM workspaces rather than a distributable artifact. By keeping the root version static, the project avoids accidental publishing of the monorepo itself and clearly signals that consumers should install individual packages rather than the root.

### Package-Level Semantic Versioning

Each package under `packages/*` maintains its own independent **semantic version** string. This allows the project to release hotfixes or major updates to individual modules without forcing version bumps across the entire ecosystem. Current examples include:

- `@cordis/core` at `"4.0.0-rc.10"`
- `@cordis/loader` at `"1.0.0-rc.7"`
- `@cordis/include` at `"1.1.0"`
- `@cordis/timer` at `"1.1.3"`
- `@cordis/logger-console` at `"1.0.0"`

Because these versions are decoupled, a change in `packages/timer` does not trigger a new release of `packages/core`.

### Internal Loader Runtime Versioning

Beyond static package versions, Cordis implements dynamic version detection inside **[`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts)**. This file defines two explicit version constants—`v1` and `v2`—and selects the appropriate implementation based on the Node.js runtime version via `process.versions.node`. The active version is exposed as `loader.version`, returning either `'v1'` or `'v2'`.

This strategy isolates breaking changes to the loader API from the package's semantic version. Plugin authors can query this property to adapt their code to the current loader capabilities.

## Detecting Runtime Loader Versions in Code

To determine which loader API is active in your environment, import the loader instance and check the `version` property:

```typescript
import { loader } from '@cordis/loader'

if (loader.version === 'v2') {
  // Use the newer loader API with enhanced capabilities
  loader.registerPlugin(myPluginV2)
} else {
  // Fall back to legacy API for older Node versions
  loader.registerPlugin(myPluginV1)
}

```

The selection logic resides in [`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts), where the library performs feature detection against the Node.js version to choose between `v1` and `v2` implementations. This ensures that applications automatically receive the optimal loader for their runtime environment.

## Reading Package Versions at Runtime

When you need to access the static semantic version of a specific Cordis package, import directly from its [`package.json`](https://github.com/cordiverse/cordis/blob/main/package.json):

```typescript
import { version as coreVersion } from '@cordis/core/package.json'

console.log('Core version:', coreVersion) // => "4.0.0-rc.10"

```

This is useful for telemetry, debugging, or compatibility checks against specific package releases.

## Key Files Defining Versioning Strategy

Several critical files implement the versioning strategies for Cordis:

- **[`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts)**: Contains the runtime loader version logic with `v1` and `v2` constants, plus Node version detection logic.
- **[`packages/core/package.json`](https://github.com/cordiverse/cordis/blob/main/packages/core/package.json)**: Declares the core library's semver (`4.0.0-rc.10`).
- **[`packages/loader/package.json`](https://github.com/cordiverse/cordis/blob/main/packages/loader/package.json)**: Declares the loader's independent semver (`1.0.0-rc.7`).
- **[`packages/include/package.json`](https://github.com/cordiverse/cordis/blob/main/packages/include/package.json)**: Declares the include package's version (`1.1.0`).
- **[`packages/timer/package.json`](https://github.com/cordiverse/cordis/blob/main/packages/timer/package.json)**: Declares the timer utility version (`1.1.3`).

These files demonstrate how Cordis separates version concerns across the monorepo, enabling flexible, independent releases while providing clear runtime capability indicators.

## Summary

- The **monorepo root** uses a fixed `0.0.0` version as a workspace placeholder, preventing accidental publication.
- **Individual packages** maintain independent **semantic versions** (e.g., `4.0.0-rc.10`, `1.1.3`), allowing isolated releases and hotfixes.
- The **loader** exposes runtime versions (`v1` or `v2`) through `loader.version`, determined by Node.js feature detection in [`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts).
- Consumers should install specific packages (e.g., `@cordis/core`) rather than the root, and query `loader.version` for runtime compatibility.

## Frequently Asked Questions

### Why does the Cordis monorepo root use version 0.0.0?

The root [`package.json`](https://github.com/cordiverse/cordis/blob/main/package.json) stays at `0.0.0` to serve exclusively as a workspace marker for package managers like Yarn or PNPM. This prevents accidental publishing of the entire monorepo and clearly indicates that the root is not a distributable package.

### How do I check which loader version my Cordis application is using?

Access the `loader.version` property after importing from `@cordis/loader`. It returns either `'v1'` or `'v2'` based on Node.js version detection performed in [`packages/loader/src/internal.ts`](https://github.com/cordiverse/cordis/blob/main/packages/loader/src/internal.ts), allowing you to branch logic for different loader capabilities.

### Can I update one Cordis package without updating others?

Yes. Because each package under `packages/*` maintains its own independent semver string, you can bump `@cordis/timer` from `1.1.3` to `1.1.4` without affecting `@cordis/core` at `4.0.0-rc.10` or any other package.

### What do the pre-release suffixes like -rc.10 indicate?

The `-rc` suffix denotes a **release candidate** version, indicating the package is in a pre-stable testing phase. For example, `4.0.0-rc.10` represents the tenth release candidate for the upcoming 4.0.0 major version of `@cordis/core`.