# Stability & semver

> What better-drizzle considers stable in the 0.3.x line, how the unified package is versioned, and what counts as a breaking change.

URL: https://better-drizzle.com/docs/reference/stability

`0.3.x` is the Drizzle ORM 1.x release line of better-drizzle.

> **0.2.0 changed how plugins are distributed:** The official plugins are no longer published as separate
> `@better-drizzle/*` packages. Everything ships inside the single
> `better-drizzle` package as subpath exports. See the
> [upgrade guide](/docs/guides/upgrading) for the one-step migration.

## One package, one version

There is a single published manifest. `better-drizzle` and every official
plugin move together, so there is no version matrix to reconcile:

```ts
import { version } from 'better-drizzle';
import { version as zodVersion } from 'better-drizzle/zod';

version === zodVersion; // always true
```

Each entrypoint still re-exports `version` so a plugin can report itself in
logs, but the value is always the package version.

## What is considered stable in `0.3.x`

* the package entrypoints listed in `exports` (`.`, `/plugins`, `/eslint`, `/rules`, `/soft-delete`, `/timestamps`, `/zod`); `/ata` and `/cache` are experimental (below)
* documented delegate methods and their result shapes
* documented client methods
* documented option names on `better()`, on each operation, and on official plugins
* the plugin authoring API: `definePlugin`, hooks, transforms, extensions, and `operationArgs`
* plugin operation intercepts: `intercept(ctx)` with `next()`, `annotate()`, `skipAfterHooks()`, and `params`, plus the `annotations` after hooks receive (see [intercepts](/docs/plugins/plugin-hooks#intercepts))
* the published [support matrix](/docs/reference/support-matrix) for PostgreSQL, SQLite, and MySQL

## Experimental in `0.3.x`

* `better-drizzle/cache` and `better-drizzle/cache/redis`: option names,
  per-call `cache` arguments, `$cache` methods, the store interface, and the
  stored entry format can change in a **patch** release while the plugin
  matures. Pin an exact version if you depend on it, and expect cached
  entries to be discarded after an upgrade. The plugin is built on
  `intercept`, which is part of the stable plugin API above; only the cache
  plugin itself is experimental.
* `better-drizzle/ata`: JSON Schema validation built on
  [ata-validator](https://ata-validator.com), intended as a faster alternative
  to `better-drizzle/zod`. Option names, the `$ata` API, and the generated
  schemas can change in a **patch** release. Pin an exact version if you
  depend on it.
* `better-drizzle/tenant` (from `0.4.0`, experimental through `0.4.x`):
  option names, the `$tenant` / `$withoutTenant` API, and error details can
  change in a **patch** release. Pin an exact version if you depend on it.
  See [tenant](/docs/plugins/tenant).

Experimental entrypoints are not covered by the semver policy below until
they move to the stable list.

Anything reachable only through a deep import path (`better-drizzle/dist/...`)
is internal and can change in a patch.

## Semver policy

better-drizzle follows semver intent, with extra conservatism around types:

* **patch** - bug fixes, doc fixes, test additions, internal optimizations, support-matrix clarifications
* **minor** - additive APIs, new plugin hooks, new documented options, new entrypoints
* **major** - behavior changes, removed exports, renamed options, changed result shapes, or stricter semantics that can break existing code

While the package is pre-1.0, a breaking change lands in a **minor** bump
(`0.2.x` → `0.3.0`) and is always called out in the release notes with a
migration path.

## Type-level compatibility

TypeScript users depend on inference as part of the product. Because of that:

* changes that break valid user code through types are treated as breaking changes
* documented generic types and exported helper types are part of the public surface
* public API snapshots are generated in the repository to make surface drift easier to review

## Dialect policy

When a dialect cannot support a feature safely or honestly, the project prefers:

1. explicit support
2. explicit unsupported behavior with a structured [error](/docs/reference/errors)

It does **not** prefer hidden userland fallbacks that materially change
performance or semantics without saying so. An `upsertMany` target MySQL cannot honor
and row [locks](/docs/advanced/locks) on SQLite fail fast for exactly this reason.

## Release notes

Every published version should have:

* a changelog entry
* updated docs when user-facing behavior changes
* a documented migration path for anything breaking
* passing smoke-consume checks against the built tarball
