SPI stability rules
At a glance
Section titled “At a glance”The NextPDF service provider interface follows Semantic Versioning. Each public contract carries a @stability tag and a backward-compatibility promise. Use these rules to decide which contracts you can depend on.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”The service provider interface includes the public contracts in the NextPDF\Contracts and NextPDF\Event namespaces. A type is part of the interface only when its source PHPDoc carries an @stability tag. The tag defines the boundary. A type without the tag is internal, even when PHP exposes it as public.
NextPDF follows Semantic Versioning 2.0.0. A breaking change to a stable contract requires a major version increment. A new contract or non-breaking addition increments the minor version. A bug fix increments the patch version.
The @stability tag
Section titled “The @stability tag”Each contract declares one of three stability values:
| Tag | Meaning | Change rule |
|---|---|---|
stable | Ready for production. Safe to depend on. | No breaking change in a minor or patch release. New methods are added only with a default behavior or on a new contract. |
experimental | Usable, but not yet frozen. | The interface may change in a minor release, with a deprecation notice first. |
deprecated | Scheduled for removal. | The contract states the replacement and the removal version. |
NextPDF records each per-contract promise in the generated contracts map and regenerates it from source on every release. The promise text gives the exact rule for that contract. Treat the contract source PHPDoc as the single source of truth.
Backward-compatibility promise classes
Section titled “Backward-compatibility promise classes”The contracts map records each promise in one of four classes:
- Interface promise. “No breaking change in a minor or patch release. New methods only with a default implementation.” Applies to most
stableinterfaces, includingFontRegistryInterface,SignerInterface,HsmSignerInterface, andHtmlSecurityPolicyInterface. - Enum promise. “No removal of cases. New cases may be added in a minor version.” Applies to
stableenums such asAlignment,Orientation, andOutputDestination. - Frozen value-object promise. “Constructor signature and public properties are frozen. New methods may be added.” Applies to value objects such as
TextPreprocessResult,TextSegment, and the event payloads bound to it. - Experimental promise. “The interface may change in a minor version with a deprecation notice.” Applies to
experimentalcontracts such asDeferredSignerInterface,TimestampProviderInterface,CursorInterface, andStreamingWriterInterface.
A final class such as EventDispatcher or ListenerProvider freezes its public method signatures. Use composition to extend a final class. Do not subclass it.
Experimental streaming contracts
Section titled “Experimental streaming contracts”CursorInterface and StreamingWriterInterface are experimental (since 3.1.0). NextPDF ships final, tested engine implementations for both contracts; the implementation classes are internal and are not part of the public surface. You consume streaming behavior through the public experimental contract. In most cases, you do not implement the contract yourself.
Because the contract is experimental, its signature may change in a minor release, with a deprecation notice first (the experimental promise). Pin tightly or wrap it behind your own adapter before you depend on it in production. Treat the streaming contract as a stabilizing extension point, not a frozen point.
API surface
Section titled “API surface”There is no runtime application programming interface (API) on this page. The relevant surface is the @stability PHPDoc tag on every public contract and the regenerated contracts map that aggregates the per-contract promise.
Code sample — Quick start
Section titled “Code sample — Quick start”Read a contract’s stability from source before you depend on it.
<?php
declare(strict_types=1);
use ReflectionClass;
$doc = (new ReflectionClass(\NextPDF\Contracts\FontRegistryInterface::class)) ->getDocComment();
// Look for the "@stability stable" line in the contract PHPDoc.\assert(\is_string($doc) && \str_contains($doc, '@stability stable'));Code sample — Production
Section titled “Code sample — Production”A Composer version constraint pins the major version, which is where breaking changes occur for a stable contract.
{ "require": { "nextpdf/core": "^3.0" }}Use ^3.0 to receive minor and patch releases without a breaking change to any stable contract. Pin more tightly when you depend on an experimental contract, because an experimental contract may change in a minor release.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- Tag, not visibility. A PHP method marked
publicis not part of the service provider interface unless its declaring type carries an@stabilitytag. - Experimental drift. An
experimentalcontract may change in a minor release. Pin tightly or wrap it behind your own adapter. This applies to the streaming contracts even though they have shipped implementations. - New default methods. A
stableinterface may gain a method that has a default behavior. Implement the new method when you upgrade so your own implementation stays explicit. - Edition parity. NextPDF Pro and NextPDF Enterprise follow the same rules. A contract you target in Core stays valid against a Premium implementation of the same contract.
Deprecation lifecycle
Section titled “Deprecation lifecycle”A contract moves through a defined lifecycle:
- Mark. The owner sets
@stability deprecatedin the source PHPDoc and records the replacement and the removal version. - Notice. The deprecation is announced in the changelog for the release that marks it.
- Overlap. The deprecated contract and its replacement coexist for at least one minor release.
- Remove. The contract is removed in the stated major release. Removal never happens in a minor or patch release.
Plan an upgrade as soon as a contract is marked deprecated. The replacement is always stated.
Performance
Section titled “Performance”This page defines policy. It has no runtime cost.
Security notes
Section titled “Security notes”Signing contracts are stable and follow the interface promise. A new method on a signing contract arrives only with a default behavior or on a new contract, so a hardware-backed implementation does not break on a minor upgrade. Review the changelog before a major upgrade, because a major version may change a stable contract.
Conformance
Section titled “Conformance”These versioning rules conform to Semantic Versioning 2.0.0. Changelog generation follows Conventional Commits 1.0.0.
Commercial context
Section titled “Commercial context”NextPDF Pro and NextPDF Enterprise follow the same service provider interface stability rules as Core. A contract you target in Core remains valid against the Premium implementation of that contract, so your extension code is portable across editions.
See also
Section titled “See also”Related contracts and modules
Section titled “Related contracts and modules”- Contracts module reference — generated contracts map and per-contract promise text.
- Streaming contracts reference —
experimentalstreaming contracts and their shipped implementations. - Signing contracts reference —
stableandexperimentalsigning contracts under the same rules. - Extension authoring overview — what each
@stabilitytag means in practice. - Action triggers and event listeners — the
finaldispatcher and experimental payloads these rules govern.
The glossary defines stability tag and backward-compatibility promise. See the published glossary for the canonical definitions.