---
title: Backward Compatibility Policy
description: Versioning strategy, deprecation timelines, breaking change policy, and migration support for ObjectStack
---

# Backward Compatibility Policy

ObjectStack follows strict backward compatibility guarantees to ensure predictable upgrades and long-term stability for production deployments.

<Callout type="info">
**Applies to:** `@objectstack/spec` and all packages in the ObjectStack ecosystem.
</Callout>

---

## Versioning Strategy

ObjectStack follows [Semantic Versioning 2.0.0](https://semver.org/) (`MAJOR.MINOR.PATCH`):

| Version Component | When Incremented | Guarantee |
|:---|:---|:---|
| **MAJOR** (X.0.0) | Incompatible API changes | May contain breaking changes |
| **MINOR** (0.X.0) | New features, backward-compatible | Existing code continues to work |
| **PATCH** (0.0.X) | Bug fixes, backward-compatible | No behavior changes, only fixes |

### SemVer Guarantees

- **Zod schemas** are part of the public API surface. Adding optional properties is a MINOR change; removing or renaming properties is a MAJOR change.
- **TypeScript types** inferred from Zod (`z.infer<typeof Schema>`) follow the same guarantees as their source schemas.
- **Helper functions** (e.g., `defineStack`, `defineStudioPlugin`) maintain their call signatures within a MAJOR version.
- **Input formats** — `defineStack()` accepts both array and map (Record) format for all named metadata collections. Both formats are guaranteed stable within a MAJOR version.
- **Enum values** are append-only within a MAJOR version. Existing values are never removed or renamed in MINOR/PATCH releases.
- **Default values** in schemas are not changed in MINOR/PATCH releases unless fixing a documented bug.

```typescript
// These imports are guaranteed stable within a MAJOR version
import { FieldSchema, ObjectSchema } from '@objectstack/spec/data';
import { defineStack } from '@objectstack/spec';
import { defineStudioPlugin } from '@objectstack/spec/studio';
```

---

## Deprecation Timeline

When a feature, schema property, or API is deprecated, ObjectStack follows a structured wind-down process:

### Phase 1: Deprecation Notice (MINOR release)

- Feature is marked `@deprecated` in JSDoc comments
- Zod schema property gets a `.describe('DEPRECATED: ...')` annotation
- Runtime warning is emitted on first use (once per session)
- Migration path is documented in the CHANGELOG

### Phase 2: Migration Period (minimum 2 MINOR releases)

- Deprecated feature continues to function without behavior changes
- Documentation is updated with migration guides
- Code examples are updated to use the replacement
- CLI tooling may provide automated migration commands

### Phase 3: Removal (next MAJOR release)

- Deprecated feature is removed from the schema
- TypeScript types no longer include the property
- Runtime code no longer supports the feature

### Timeline Summary

```
v3.2.0  →  Feature deprecated (warning emitted)
v3.3.0  →  Migration period continues
v3.4.0  →  Migration period continues (minimum 2 minor releases)
v4.0.0  →  Feature removed (earliest possible removal)
```

<Callout type="warn">
**Minimum guarantee:** Deprecated features survive for at least **2 MINOR releases** before they can be removed in the next MAJOR version.
</Callout>

---

## Breaking Change Policy

### What Constitutes a Breaking Change

| Change Type | Breaking? | Version Impact |
|:---|:---|:---|
| Removing a schema property | **Yes** | MAJOR |
| Renaming a schema property | **Yes** | MAJOR |
| Changing a property from optional to required | **Yes** | MAJOR |
| Narrowing a type (e.g., `string` → `enum`) | **Yes** | MAJOR |
| Removing an enum value | **Yes** | MAJOR |
| Changing default values | **Yes** | MAJOR |
| Adding a new optional property | No | MINOR |
| Adding a new enum value | No | MINOR |
| Widening a type (e.g., `enum` → `string`) | No | MINOR |
| Adding a new schema/export | No | MINOR |
| Fixing validation to match documented behavior | No | PATCH |
| Fixing typos in descriptions | No | PATCH |

### Breaking Change Process

1. **RFC (Request for Comments)** — Breaking changes are proposed as GitHub issues with the `breaking-change` label.
2. **Review Period** — Minimum 30-day community review period.
3. **Deprecation** — The old behavior is deprecated in a MINOR release (see timeline above).
4. **Migration Guide** — A detailed migration guide is published before the MAJOR release.
5. **Release** — Breaking change ships in the next MAJOR version.

---

## Migration Support

### Automated Migrations

ObjectStack provides tooling to ease upgrades across MAJOR versions:

```bash
# Check for deprecated usage in your project
npx @objectstack/cli lint --deprecations

# Auto-migrate to the latest schema version
npx @objectstack/cli migrate --from 3.x --to 4.x
```

### Migration Guides

Each MAJOR release includes:

- **CHANGELOG.md** — Complete list of changes with migration notes
- **RELEASE_NOTES.md** — High-level summary and upgrade instructions
- **Codemods** — Automated code transformations where possible
- **Schema Diff** — Machine-readable diff of all schema changes

### Support Windows

| Version | Status | Support Level |
|:---|:---|:---|
| Current MAJOR (N) | **Active** | Full feature development, bug fixes, security patches |
| Previous MAJOR (N-1) | **Maintenance** | Critical bug fixes and security patches only |
| Older versions (N-2+) | **End of Life** | No support; upgrade recommended |

---

## Spec Package Guarantees

The `@objectstack/spec` package provides additional stability guarantees:

### Schema Stability

- All Zod schemas are validated by comprehensive test suites
- Schema changes require both Zod and JSON Schema output validation
- Property additions must include `.describe()` annotations and `.optional()` or `.default()` markers

### Export Stability

- All public exports are listed in the package's `index.ts` barrel files
- Removing an export is always a MAJOR change
- Internal modules (prefixed with `_` or in `internal/` directories) are not covered by SemVer guarantees

### Runtime Behavior

- `z.parse()` results are guaranteed consistent within a MAJOR version
- Default values applied by `.default()` are stable within a MAJOR version
- Validation error messages may change in MINOR/PATCH releases (do not rely on exact error text)

---

## Pre-1.0 Disclaimer

<Callout type="warn">
During the **0.x** development phase, MINOR versions may contain breaking changes. The full backward compatibility policy takes effect starting with version **1.0.0**.
</Callout>

---

## Reporting Compatibility Issues

If you encounter an unintended breaking change:

1. **Check the CHANGELOG** — Verify the change was not documented as intentional.
2. **Open an issue** — File a GitHub issue with the `compatibility` label.
3. **Include a reproduction** — Provide a minimal code sample showing the breakage.
4. **Reference the version** — Specify the exact versions where behavior changed.
