Reference documentation that never gets outdated
Define once. Generate everything else.
Most teams maintain configuration properties twice. Code defines them. Docs describe them.
Then things drift apart.
The problem
Engineer adds a new configuration property:
export interface DatabaseConfig {
isolationLevel?: IsolationLevel;
enableSsl?: boolean;
retryAttempts?: number; // New property
}Deploys it. Forgets to update the docs.
Three weeks later, a user reads the documentation. No mention of retry_attempts. They assume the feature doesn’t exist. Or worse, they assume the default behavior and it breaks their setup.
Support ticket arrives.
This pattern repeats with every config change. Properties added, docs lag behind. Properties deprecated, docs still show them. Default values change, docs show old defaults. The same thing happens with API parameters, CLI flags, environment variables, error codes. Anywhere docs describe what exists in code.
The root cause is simple: code and docs live in two places with different owners. Code changes frequently, gets reviewed and tested, and is always correct. Docs update manually, have no automated checks, and drift out of sync. Two systems that don’t talk to each other.
The solution: define once, generate the rest
There are two approaches.
Approach 1: Define a schema
Write a machine-readable schema as your source of truth. From it, generate code, docs, and everything else.
properties:
- name: isolation_level
required: true
type: string
enum: [READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE]
example: READ_UNCOMMITTED
description: Transaction isolation level
- name: enable_ssl
required: false
type: boolean
default: true
description: Enable SSL encryption for database connections
- name: retry_attempts
required: false
type: integer
default: 3
description: Number of times to retry failed connectionsFrom this schema, generate server code, client SDKs, API documentation, examples, interactive API explorers. The schema is your contract. Everything else derives from it.
An additional benefit: by decoupling the schema from actual code, you facilitate conversations about the contract. Teams can review and agree on the API structure before implementation.
This approach works best when open standards exist for your technology: OpenAPI for REST APIs, GraphQL schemas, Protocol Buffers for gRPC, JSON Schema, AsyncAPI for event-driven architectures.
If no standard exists, you need to build the generators yourself, which could be a stopper if resources are limited.
Approach 2: Annotate your code
Add documentation as annotations directly in your code. Generate docs from it.
Example: TypeScript with JSDoc
export interface DatabaseConfig {
/** Transaction isolation level
* @required
* @example ‘READ_COMMITTED’
*/
isolationLevel?: IsolationLevel;
/** Enable SSL encryption for database connections
* @default true
*/
enableSsl?: boolean;
/** Number of times to retry failed connections
* @default 3
*/
retryAttempts: number;
}
From annotated code, generate the intermediate schema and the reference documentation.
Check if your programming language already has a standard: JavaDoc for Java, Google-style docstrings for Python, JSDoc for TypeScript/JavaScript. If no convention exists, define one. Document it. Stay consistent.
This approach is simpler than defining schemas, especially when you don’t have code generators available.
How to implement it
Document your source of truth. Write your schema file or add annotations to your code. Include descriptions, types, defaults, constraints.
Be thorough. This is the single source. Everything generates from it.
Choose your generator. Check if existing plugins work for your docs platform. Rendering OpenAPI in Docusaurus? There’s a plugin. Sphinx? Extension available.
But if you need something specific (TypeScript docs in Antora, for example), you’ll need a custom solution.
Key tip for annotations: Always generate an intermediate schema file (JSON or YAML) first. Don’t try parse code annotations directly in your docs build.
If you need a custom extension, that requires dev work. We can help with that.
Add to CI. On every commit: validate the source, regenerate documentation, fail the build if validation fails. On merge: deploy updated documentation automatically.
Start small
You don’t need to generate everything on day one.
Start with one configuration file. Generate just the reference table. Keep the rest manual. You can still have custom, hand-written guides alongside generated reference sections. Prove it works. Then expand.
A common objection
“But our configuration is complex. We need custom documentation.”
You can still have it. Generate the reference section (the part that can be autogenerated and reused in guides). Keep step-by-step guides manual.
The result
Engineer adds a new parameter. Commits the code. The docs update automatically.
Three weeks later, a user reads the documentation. The parameter is there.
No support ticket this time.



