Add a Provider¶
This guide walks through creating a new cdkx provider from scratch — the packages, the base classes to extend, and how the pieces plug into the engine. The Hetzner provider is the reference implementation throughout.
Overview¶
A provider in cdkx consists of two packages:
| Package | Role |
|---|---|
@cdk-x/<name> |
Synth package — L1 construct classes, JSON schemas, codegen. Used by the user's TypeScript app at synth time. |
@cdk-x/<name>-runtime |
Runtime package — ResourceHandler implementations, SDK facade, ProviderAdapterFactory. Used by the engine at deploy time. |
The split is intentional: synth packages have no runtime dependencies, so a user's app only imports lightweight construct code.
Step 1 — Create the synth package¶
Generate the package with Nx:
npx nx g @nx/js:library packages/providers/<name>/<name> \
--name=@cdk-x/<name> --importPath=@cdk-x/<name> \
--bundler=tsc --publishable --unitTestRunner=jest \
--linter=eslint --minimal --useProjectJson --no-interactive
Then align the generated files — see the New library checklist section in CLAUDE.md at the repository root for the exact steps (remove "type": "module", set "exports" to use "require", add "publishConfig", etc.).
Implement Provider¶
Create src/lib/provider/provider.ts:
- Must be lowercase, URL-safe, and unique. Written into
manifest.jsonas theproviderfield for each stack artifact. The runtime package reads this to look up the correctProviderAdapterFactory.
The Provider base class has three overridable methods:
| Method | Default | Override when |
|---|---|---|
getResolvers() |
[] |
You need custom token transformations at synth time |
getSynthesizer() |
JsonSynthesizer |
You want YAML output or a custom format |
getEnvironment() |
{} |
You want to write deploy-target metadata to manifest.json |
Add JSON schemas and codegen¶
For providers that model their resources as JSON Schemas (recommended), set up the same codegen pipeline as Hetzner:
- Create
schemas/v1/in the synth package root. - Add a
codegentarget toproject.jsonusing@cdk-x/spec-to-cdkx. - Write one schema per resource type. See Add a Resource Handler for the schema format.
- Run
npx nx run @cdk-x/<name>:codegento generate the L1 construct classes.
Skipping codegen
You can write L1 constructs by hand by extending ProviderResource directly. Codegen is a convenience — it is not required. See Construct for the manual approach.
Step 2 — Create the runtime package¶
npx nx g @nx/js:library packages/providers/<name>/<name>-runtime \
--name=@cdk-x/<name>-runtime --importPath=@cdk-x/<name>-runtime \
--bundler=tsc --publishable --unitTestRunner=jest \
--linter=eslint --minimal --useProjectJson --no-interactive
Apply the same alignment checklist. Add @cdk-x/core and @cdk-x/engine as dependencies.
New library checklist
The full alignment checklist (package.json, tsconfig, project.json, jest config) is documented in CLAUDE.md at the repository root under the New library checklist section.
SDK facade¶
Wrap the provider's API client in a facade class. This keeps handler code testable — tests inject a stub SDK without needing to mock HTTP:
- The underlying API SDK. Can be any HTTP client — auto-generated OpenAPI clients, Axios wrappers, etc.
ProviderRuntime¶
- The type string must exactly match
typeNamein the schema andRESOURCE_TYPE_NAMEon the L1 class.
ProviderAdapterFactory¶
This is the glue between the runtime package and the engine. It reads credentials from the environment and builds a RuntimeAdapter:
RUNTIME_CONFIGSis auto-generated by codegen fromprimaryIdentifierandcreateOnlyPropertiesin each schema.- Must match
Provider.identifierin the synth package. - Read credentials from environment variables — never hardcode them.
Step 3 — Register the factory with the engine¶
The CLI discovers provider adapters through an AdapterRegistry. Open the registry configuration (in @cdk-x/cli) and add your factory:
Step 4 — Write resource handlers¶
With the package scaffolding in place, add handlers for each resource type. See Add a Resource Handler for the step-by-step process.
Package dependencies¶
| Package | Depends on |
|---|---|
@cdk-x/<name> (synth) |
@cdk-x/core, constructs, tslib |
@cdk-x/<name>-runtime |
@cdk-x/core, @cdk-x/engine, @cdk-x/<name> (for RUNTIME_CONFIGS) |
See also
- Add a Resource Handler — add individual resource support within the provider
packages/providers/hetzner/hetzner/AI.md— full Hetzner synth package design (in the repo)packages/providers/hetzner/hetzner-runtime/AI.md— full Hetzner runtime design (in the repo)- Construct — the
ProviderResourcebase all L1s extend