Skip to content
docuconf
docuconf on GitHub

SDK requirements

A docuconf SDK has one job: let an app declare its configuration in the way its ecosystem already does, and add what is missing for a platform contract. There are 16 SDKs today: Go, TypeScript (T3 Env and NestJS config), .NET, Python, Ruby, Java, Kotlin, Rust, Swift, Elixir, Gleam, C++, PHP (Laravel and Symfony) and COBOL. Each has a Get started page.

Build on the host library

Every language already has a configuration library teams trust. An SDK must extend it, not replace it. The host keeps loading, parsing and binding; its users keep its API, docs and idioms. The SDK adds only:

  1. Metadata the host cannot express — descriptions, secret, constraints with no host equivalent.
  2. Validation the host does not do, run after the host has parsed.
  3. Contract export, from the same declaration, so the contract cannot drift from the code.

Each SDK sets the contract's encoding fields to whatever its host parses, so the host never needs a custom parser for platform-rendered values. Where the host conflicts with a rule in the spec (for example, empty-string handling), the SDK adapts the host with a pre-check.

Cloud-native by default

Every SDK must work however the configuration arrives:

  • Environment variables set in the pod spec — literals and Kubernetes references.
  • Values injected at runtime — Bank-Vaults' vault-env, wrappers such as op run or doppler run, operators and webhooks. The SDK reads the process environment when the process starts, after injection, and validates injected values exactly like any other. It never resolves secret references itself and never reads configuration at build time.
  • Files mounted or written at runtime — Secrets, ConfigMaps, CSI volumes, cert-manager certificates, Vault Agent templates — checked at boot and, with reload: watch, reloaded when they rotate.
  • Config-file overlays on hosts that layer files — a platform-mounted appsettings.Production.json, application.yml or Config.toml, loaded between the baked-in files and the environment.

See Inputs for how the contract and the platform describe each case.

Requirements

A conforming SDK must:

  1. 1
    Idiomatic declaration. Cover every variable type, file type and field, in the host library’s own style.
  2. 2
    Validate the declaration. At definition time: name format, description length, details not blank and at most 4000 characters, default against constraints, no default on required, RE2-only patterns, no watch where reload is unsupported.
  3. 3
    Export a conforming contract. Deterministic, sorted by name, canonical durations (1h30m), encodings set to what the host parses, narrow integer ranges exported as min/max, full-match patterns anchored as ^(?:p)$.
  4. 4
    Load from the process environment, at process start. Read the real environment when the process starts, after any injection (Bank-Vaults, Vault Agent, wrappers such as op run), and validate injected values exactly like any other. Never resolve secret references itself, and never read configuration at build time. A .env file is opt-in for development, and real variables override it.
  5. 5
    Support config-file overlays (hosts that layer files). Declare overlay files in the contract, load them in the documented order (base file < profile file < platform overlay < environment variables), and reload them when declared watch. Applies to .NET, Spring, Rails, figment and Hoplite; other hosts reject overlays at declaration time.
  6. 6
    Report every violation at boot. All together, each with a stable error code, never printing a secret value; also to /dev/termination-log. Length limits count characters (Unicode code points), and a value outside them is out_of_range.
  7. 7
    Expose typed values. A struct, class or inferred type — never a string map.
  8. 8
    Check every file input at boot. Existence, readability and size; config files parse and bind; TLS key match, validity window, minRemaining, DNS names, key algorithm and chain; CA bundle count; keystore opens; text constraints.
  9. 9
    Honour reload: watch. Reload watched files (Kubernetes swaps a symlink), or reject watch at declaration time.
  10. 10
    Ignore undeclared variables. HOSTNAME, KUBERNETES_* and the like. The unknown-name check applies only to platform values.
  11. 11
    Support DOCUCONF_FILE_ROOT. A directory prepended to every absolute file path, for local runs and tests.
  12. 12
    Offer a contract-first mode. Validate an environment against a contract.json with no in-language declaration, parsing every list and duration encoding. The conformance runner uses it.
  13. 13
    Pass the conformance suite. Every case in docuconf-go’s conformance/cases.json, run through the contract-first mode: the same typed values or the same error codes in every language.

And should:

  1. 1
    Export details. From the language’s natural doc location, beside the description. docuconf docs generates the documentation from the contract; an SDK needs no generator of its own.
  2. 2
    Framework integration. A Railtie, ValidateOnStart in .NET, a Next.js or NestJS adapter, a Spring auto-configuration.
  3. 3
    Warn on feature-flag names. Variables matching ^(FF|FEATURE|FEATURE_FLAG|ENABLE)_ are probably flags.
  4. 4
    Detect unresolved injection references. Fail with invalid_type when a secret still holds an injector reference (vault:, op://, ref+) because the injector did not run.
  5. 5
    Warn on Unicode regex classes. Where the host’s \d, \w, \s, \b are Unicode-aware but RE2’s are ASCII.

Boot-time error codes

Every violation found at boot is reported with one of these codes, so platforms and alerting can act on them the same way in every language. Length limits use out_of_range; an expired certificate, a disallowed key algorithm or a broken chain is certificate_invalid; a CA bundle with too few certificates is file_malformed.

Boot error codes
CodeMeaning
missing_requiredA required variable or file input has no value.
invalid_typeThe value does not parse as its type.
out_of_rangeOutside min/max or the 64-bit range, a list item outside itemMin/itemMax, or a string, url, json value, list item or text file outside its length limits (counted in characters).
pattern_mismatchA string or text file does not match its pattern.
not_in_enumNot one of the enum’s values.
invalid_schemeA URL with a scheme not in schemes.
too_few_itemsA list shorter than minItems.
too_many_itemsA list longer than maxItems.
file_missingA file input’s path does not exist.
file_unreadableThe path exists but cannot be read.
file_too_largeLarger than maxSize.
file_malformedDoes not parse in its format, or a CA bundle with too few certificates.
schema_mismatchA config file or json value does not match its schema.
certificate_invalidUnparseable, expired, not yet valid, disallowed key algorithm, or a broken chain.
certificate_expiringValid, but with less than minRemaining left.
certificate_name_mismatchDoes not cover every name in dnsNames.
key_mismatchThe private key does not match the certificate.
keystore_unreadableThe keystore does not open with its password.

The SDKs today

What each docuconf SDK supports, from each repository's main branch, checked 2026-10-08.
SDKHost libraryPackageVariable typesListsDurationsConfig filesKeystoresreload: watchProfilesExportConformanceExample
Gocaarlos0/env v11github.com/docuconf/docuconf-goall 9csvgojson, yamlPKCS#12all file types—docuconf export -pkg -type134 of 134net/http
TypeScript (T3 Env)T3 Env + Zod 4@docuconf/t3 (npm)all 9csvgojson, yamlPKCS#12 (JKS: format check)all file types—npx docuconf-t3 export src/env.ts131 of 134 (skips int64, json-schema)T3 Env
TypeScript (NestJS)@nestjs/config + class-validator@docuconf/nestjs (npm)all 9csvgojson, yamlPKCS#12 (JKS: format check)all file types—npx docuconf-nestjs export src/orders.config.ts131 of 134 (skips int64, json-schema)NestJS
.NETOptions pattern + appsettingsDocuconf.Options (NuGet)all 9indexedtimespanjsonPKCS#12tls, caBundle, keystore, binaryappsettings.{Environment}.jsondotnet app.dll docuconf export132 of 134 (skips json-schema)ASP.NET Core
Pythonpydantic-settings 2docuconf-pydantic (PyPI)all 9json (csv opt-in)iso8601json, yaml, tomlPKCS#12all file types—docuconf export mod:Settings134 of 134 (json-schema with the jsonschema extra)http.server
Rubyanyway_config 2docuconf-anyway (RubyGems)all 9csviso8601json, yaml, tomlPKCS#12 (JKS: format check)all file typesRails YAML (RAILS_ENV)rails docuconf:export134 of 134Rack
Java (Spring Boot)Spring Boot 3 / 4 @ConfigurationPropertiesdev.docuconf:docuconf-spring (Maven)all 9csviso8601json, yaml, tomlPKCS#12, JKSall file typesapplication-{profile}.ymlannotation processor at compile time134 of 134Spring Boot
KotlinHoplite 3dev.docuconf:docuconf-hoplite (Maven)all 9csviso8601json, yaml, tomlPKCS#12, JKSnot offered—Gradle plugin: docuconfExport134 of 134JDK HttpServer
Rustfigment + serdedocuconf (crates.io)all 9jsongojson, yaml, tomlPKCS#12rejected at declarationfigment profilesdocuconf::export()134 of 134std::net
Swiftswift-configurationDocuconf (SwiftPM)all 9csvsecondsjson, yamlPKCS#12, JKS (integrity check)when the app consumes changes—app docuconf-export132 of 134 (skips json-schema)POSIX sockets
Elixirconfig/runtime.exsdocuconf (Hex)all 9csvgojson (yaml, toml via a decoder)PKCS#12, JKS (integrity check)with Docuconf.Watcher—mix docuconf.export134 of 134:httpd
Gleamenvoy + gleam/dynamic/decodedocuconf_gleam (Hex)all 9csvgojson (others via a parser)format check onlynot offered—docuconf.write_contract()132 of 134 on Erlang, 131 on JavaScript (skips json-schema; int64 on JavaScript)wisp
C++CLI11docuconf (CMake FetchContent)all 9csvgojson, yaml, tomlPKCS#12, JKS (integrity check)rejected at declaration—app --docuconf-export134 of 134cpp-httplib
PHP (Laravel)Laravel config + vlucas/phpdotenvdocuconf/docuconf (Packagist)all 9csvgojson, yaml, tomlPKCS#12, JKS (integrity check)rejected at declaration—php artisan docuconf:export134 of 134Laravel
PHP (Symfony)Symfony config + %env()% processorsdocuconf/docuconf (Packagist)all 9csvgojson, yaml, tomlPKCS#12, JKS (integrity check)rejected at declaration—bin/console docuconf:export134 of 134Symfony
COBOLGnuCOBOL copybooks + docuconf execdocuconf-cobol (Go module)all 9csvgojson, yaml (checked by docuconf exec)PKCS#12 (checked by docuconf exec)not offered—docuconf-cobol generate134 of 134 (loader under docuconf exec)batch job

Known gaps

  • Go: caarlos0/env parses int as 32-bit, so that range is exported. No TOML config files, no JKS keystores.
  • TypeScript (T3 Env): ESM (.mjs) and CommonJS both supported. int is limited to the safe-integer range. Tested with Zod 4; other Standard Schema validators (Valibot, ArkType) are untested.
  • TypeScript (NestJS): ESM and CommonJS builds; NestJS 11 (CommonJS) and 12 (ESM). int is limited to the safe-integer range.
  • .NET: Platform-mounted appsettings overlays load through AddDocuconfOverlays<T>(). Export runs at runtime; a build-time source generator is planned.
  • Python: No JKS keystores. No profiles.
  • Ruby: Rails credentials must be excluded explicitly. TOML needs the tomlrb gem.
  • Java (Spring Boot): Several active profiles at once (a,b) are not supported yet. The dev.docuconf Maven namespace is not verified on Maven Central yet.
  • Kotlin: JVM target only so far; the core module is Kotlin Multiplatform-ready. No reload: watch.
  • Rust: No reload: watch. No JKS keystores.
  • Swift: Built and tested on Linux; macOS and iOS builds are untested. No TOML, no profiles.
  • Elixir: Watched files reload only while the app supervises Docuconf.Watcher.
  • Gleam: Keystores are not opened with their password yet. On the JavaScript target, integers beyond 2^53 lose precision. The Hex package is `docuconf_gleam`: `docuconf` is the Elixir SDK's.
  • C++: No reload: watch. No profiles or config-file overlays. JKS keystores are checked by their integrity digest; their entries are not parsed.
  • PHP (Laravel): No profiles or config-file overlays. No reload: watch. Run php artisan config:cache when the container starts, not in the image build.
  • PHP (Symfony): No profiles or config-file overlays. No reload: watch. No Flex recipe yet: register the bundle by hand.
  • COBOL: Patterns, URL schemes, JSON Schemas and file contents are checked by docuconf exec, not by the loader. A PIC X field holds bytes and contract lengths count characters: leave room for multi-byte UTF-8, or restrict values to ASCII. A value loses its trailing spaces.

Conformance suite

The shared suite lives in conformance/ in docuconf-go. Cases are written once, in YAML, and expanded into cases.json, which every SDK runs in CI through its contract-first mode:

  • Values cases start from typed platform values. They are rendered with the meta-schema's #Render once per list and duration encoding, so one case checks that every SDK reads a,b, ["a","b"] and NAME__0/NAME__1 the same way, and 1m30s, PT90S, 90 and 00:01:30 as the same duration.
  • Env cases give the raw environment the app might see anyway (malformed values, out-of-range numbers, unresolved vault: references) with the exact error codes every SDK must report.
  • A runner checks the typed result of every variable, or the exact set of variable and code pairs, and that no error output contains a secret's value.

Two SDKs that disagree on a case cannot both be right, so a failing case is a bug in an SDK or in the spec. The suite covers variables today; file inputs, profiles and overlays are tested inside each SDK until their cases are added. Each SDK's export is also checked with cue vet against the meta-schema in its own CI.