Contracts: 41 public interfaces (SPI)
At a glance
Section titled “At a glance”NextPDF\Contracts is the public service-provider interface (SPI): 41 interfaces and enums under src/Contracts/ with an explicit @stability tag and a backward-compatibility promise. Extension packages, framework bridges, and the Pro and Enterprise editions depend on these types, never concrete classes.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”The engine exposes two surfaces. Concrete classes under src/Core/, src/Html/, and src/Writer/ have no compatibility promise and can change between minor versions. The Contracts namespace works differently. It is a curated set of types with signatures frozen for the stability tier they declare. Everything outside the engine depends on this namespace, and nothing deeper. That includes the Laravel, Symfony, and CodeIgniter bridges, the compat-tcpdf shim, NextPDF Server, and the Pro and Enterprise editions.
Each contract declares one of four tiers in its PHPDoc. A stable contract allows no breaking change in a minor or patch release. New methods arrive only with default implementations. An experimental contract may change in a minor release with a deprecation notice. A deprecated contract names its replacement. A small number are contract-only, such as StreamingWriterInterface and CursorInterface. The type is published and frozen, but no production implementation ships yet.
The authoritative tier list is docs/extension-points.json (manifest version 3.0.0, 67 published points across Contracts and Event). A machine-verifiable test, tests/Unit/Contracts/StabilityContractTest.php, reads that manifest and fails the build under five conditions. First, a listed type is missing. Second, a reflected kind disagrees with the manifest. Third, an @stability PHPDoc tag drifts from the manifest. Fourth, a contract under src/Contracts/ is absent from the manifest. Fifth, an @internal type leaks into it. The contract surface cannot drift undetected.
Contracts fall into nine domains, each covered by a dedicated page: document construction, signing, barcode encoding, typography, security policy, extraction, observability, and streaming. The split mirrors how you adopt the engine. You depend on the document contract to generate Portable Document Format (PDF) files. You depend on the signing contracts to add a signature. You depend on the security-policy contracts to constrain untrusted HTML.
Optional implementation resolution follows one pattern across the engine. Core checks for a concrete class with class_exists() and casts it to the contract. LtvManagerInterface and PdfAManagerInterface resolve their Pro implementations this way. Core stays Apache-2.0 with no hard dependency on commercial code.
API surface
Section titled “API surface”| Contract | Kind | Stability | Since | Domain |
|---|---|---|---|---|
PdfDocumentInterface | interface | stable | 1.0.0 | document |
DocumentFactoryInterface | interface | stable | 1.7.0 | document |
ResettableService | interface | stable | 1.7.0 | document |
OutputDestination | enum | stable | 1.0.0 | document |
Orientation | enum | stable | 1.0.0 | document |
Alignment | enum | stable | 1.0.0 | document |
SignerInterface | interface | stable | 1.0.0 | signing |
HsmSignerInterface | interface | stable | 1.0.0 | signing |
DeferredSignerInterface | interface | experimental | 3.0.0 | signing |
TimestampProviderInterface | interface | experimental | 3.0.0 | signing |
LtvManagerInterface | interface | stable | 1.10.0 | signing |
CryptoPolicyInterface | interface | stable | 1.9.0 | signing |
Barcode1DEncoderInterface | interface | stable | 1.0.0 | barcode |
Barcode2DEncoderInterface | interface | stable | 1.0.0 | barcode |
BarcodeEncoderInterface | interface | stable | 3.0.0 | barcode |
Gs1DataParserInterface | interface | stable | 1.0.0 | barcode |
FontRegistryInterface | interface | stable | 1.7.0 | typography |
TextPreprocessorInterface | interface | stable | 1.9.0 | typography |
HtmlSecurityPolicyInterface | interface | stable | 3.1.0 | security-policy |
ExternalResourcePolicyInterface | interface | stable | 4.0.0 | security-policy |
InspectorInterface | interface | experimental | 2.2.0 | extraction |
EmbeddingServiceInterface | interface | experimental | 2.1.0 | extraction |
VectorIndexInterface | interface | experimental | 2.1.0 | extraction |
JobNotificationInterface | interface | experimental | 2.2.0 | observability |
SpectrumInterface | interface | experimental | 2.1.0 | observability |
StreamingWriterInterface | interface | experimental | 3.1.0 | streaming |
CursorInterface | interface | experimental | 3.1.0 | streaming |
The table lists the primary contracts. The remaining types, including value-object data transfer objects (DTOs) (TextSegment, TextPreprocessResult), the EInvoice sub-namespace, behavior enums (DegradationPolicy, UnderlineStyle), and import contracts (ImportedFormObjectInterface, EmbeddedPdfObjectInterface, ChromeRenderResultInterface), are documented on the domain pages under See also. The full machine-readable list is docs/extension-points.json, mirrored to .ai/contracts-map.md.
Code sample — Quick start
Section titled “Code sample — Quick start”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Hello World');$doc->addPage();$doc->setFont('helvetica', '', 24);$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);$doc->save(__DIR__ . '/output/01-hello-world.pdf');Document::createStandalone() returns a concrete Document that satisfies PdfDocumentInterface. Type-hint the interface in your services so engine internals stay swappable.
Code sample — Production
Section titled “Code sample — Production”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Core\PdfFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
// Created once at process boot in a RoadRunner/Swoole/Octane worker.$fontRegistry = new FontRegistry();$imageRegistry = new ImageRegistry(maxCacheBytes: 50 * 1024 * 1024);$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$factory = PdfFactory::new() ->withCompress(true) ->withDocumentFactory($documentFactory);
for ($request = 1; $request <= 3; $request++) { $doc = $factory->create(); $doc->setTitle("Worker Request #{$request}"); $doc->addPage(); $doc->setFont('helvetica', 'B', 16); $doc->cell(0, 12, "Worker Request #{$request}", newLine: true); $doc->save(__DIR__ . "/output/14-worker-request-{$request}.pdf");}DocumentFactory implements DocumentFactoryInterface. It holds process-lifetime FontRegistryInterface and ImageRegistryInterface singletons and injects them into each disposable Document, so a worker parses each font once across thousands of requests.
Edge cases & gotchas
Section titled “Edge cases & gotchas”- A contract-only type compiles but has no runtime backing. A
newexpression againstStreamingWriterInterfaceorCursorInterfacecannot succeed because no class implements them yet. Treat them as a forward-declared application programming interface (API). - The
@stabilityPHPDoc tag is the source of truth for a single type.docs/extension-points.jsonis the source of truth for the set. When they disagree,StabilityContractTestfails. Do not hide the disagreement by editing one side. experimentaldoes not mean unstable in practice. It means the compatibility promise is weaker. Read each contract’sbc_promisefield in.ai/contracts-map.mdbefore pinning to it.- An
@internalclass is never a contract even if other packages can technically reference it. The stability test rejects any@internaltype that appears in the manifest. - Adding a method to a
stableinterface is a breaking change for implementers unless the method ships with a default implementation. The engine adds capability through new interfaces, not by widening existing ones.
Performance
Section titled “Performance”Programming against Contracts adds no measurable runtime cost: an interface type-hint resolves at link time, not per call. The performance_budget for this page’s worker example is 1500 ms wall and 64 MB peak across three documents. Font parsing on the first request dominates that budget. Later requests reuse the registry cache and drop to single-digit milliseconds of contract-attributable work. The cost model is O(1) per contract dispatch; the work is in the concrete implementation, documented on each domain page.
Security notes
Section titled “Security notes”The SPI is also a security boundary. HtmlSecurityPolicyInterface and ExternalResourcePolicyInterface are deny-by-default contracts that constrain what untrusted HTML can do before it reaches a renderer. CryptoPolicyInterface gates algorithm and key-strength selection for signing and encryption. Because these are contracts, you can supply a stricter policy without forking the engine. Pin to the stable tier for any security-relevant policy. Experimental policy contracts may change shape between minor releases. The signing and security-policy domain pages carry the full threat model and normative references.
Conformance
Section titled “Conformance”This overview makes no direct normative claim; each domain page renders its own citations block. The signing contracts map to ISO 32000-2 §12.8 (digital signatures) and ETSI EN 319 142 (PAdES baselines). The PDF/A manager maps to ISO 19005-4. See the signing, security-policy, and extraction pages for clause-level conformance tables.
Commercial context
Section titled “Commercial context”The Pro and Enterprise editions provide the production code behind several core contracts: LtvManagerInterface (long-term validation), PdfAManagerInterface (PDF/A enforcement), the Hardware Security Module (HSM) and deferred signers, the barcode encoders, and the embedding and vector-index contracts. Core publishes and freezes the interface; the Premium package ships the implementation. This keeps the open-source engine Apache-2.0 and gives commercial deployments a drop-in upgrade with no API change.
See also
Section titled “See also”- Contracts / Document — PDF document, factory, and registry contracts.
- Contracts / Signing — signer, HSM, timestamp, and long-term validation (LTV) contracts.
- Contracts / Security Policy — crypto, HTML, and resource policy contracts.
- Contracts / Typography — font registry and text-preprocessing contracts.
- Contracts / Extraction — inspector, PDF/A, embedding, and e-invoice contracts.
- Core — concrete classes that satisfy these contracts.
- Event — the event SPI counterpart published alongside
Contracts.