Bringing documentation into the workflow with TechDocs: understanding the docs-as-code concept using MkDocs and techdocs-core, arranging the docs folder structure, marking entities with the backstage.io/techdocs-ref annotation, and building and publishing documentation with techdocs-cli to local or cloud storage such as S3, GCS, and Azure Blob.

In episode 6, you built a golden path with the Scaffolder — new components are born complete with structure, repository, and a catalog entry. Episode 7 completes that component with something often treated as an afterthought: documentation. We dive into TechDocs — Backstage's way of treating documentation as part of the workflow, not an attachment that quickly goes stale. The goal is simple: every engineer opens a component's page in Backstage, and accurate documentation is already there, always in sync with the version of the code that's running.
Good documentation often fails not because of its content, but because of the process: it's written in Google Docs, its versions float around, and the release date is never clear. Docs-as-code solves this by treating documentation exactly like code:
TechDocs takes this model a step further: the documentation pages appear inside Backstage itself, on the same page as the related component entity. You don't need to visit an external wiki — the documentation is right where you work.
TechDocs uses MkDocs as its generator: it reads Markdown files and produces a fast static site. The key is the techdocs-core plugin — a single extension package provided by Backstage that adds documentation components like tabs, code blocks with specific languages, and the MkDocs Material theme integration. The MkDocs configuration lives in the mkdocs.yml file at the root of the repository.
site_name: 'payment-api-docs'
docs_dir: docs
plugins:
- techdocs-core
nav:
- Overview: index.md
- Getting Started: getting-started.md
- API: api.md
markdown_extensions:
- mkdocs-awesome-pages-plugin.v2
- mkdocs-monorepo-plugindocs_dir points to the docs folder, plugins contains techdocs-core, and nav arranges the navigation menu. techdocs-core bundles several MkDocs plugins into one package, so you only mention it once instead of managing a dozen plugins one by one.
Documentation is stored in the docs/ folder inside the repository, containing Markdown files. TechDocs supports standard Markdown syntax, and with techdocs-core you can also use advanced features like tabs and diagrams. A tidy structure usually looks like this:
docs/
index.md
getting-started.md
api.md
images/
architecture.png
mkdocs.ymlThe first page is usually docs/index.md, and the menu order is determined by nav in mkdocs.yml. Images are stored in the docs/images subfolder so they get built too. Don't put images outside docs_dir — MkDocs only processes files inside that folder.
For TechDocs to know that a repository contains documentation, add the backstage.io/techdocs-ref annotation to the entity in catalog-info.yaml. Its value points to the location of the mkdocs.yml file — usually the directory itself.
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-api
annotations:
backstage.io/techdocs-ref: dir:.
spec:
type: service
owner: group:platform-teamThe value dir:. means the documentation lives at the root of the repository. Without this annotation, the TechDocs tab on the component page will find nothing, and the documentation build won't connect to the correct entity.
To see the results locally, use techdocs-cli (the @techdocs/cli package). The generate command runs MkDocs and produces a static site, while serve displays it for an interactive preview in the browser.
npx @techdocs/cli generate
npx @techdocs/cli servegenerate reads docs/ and mkdocs.yml, then produces a static documentation folder inside the repository. serve opens an interactive preview in the browser. Both must be run in the repository directory that contains mkdocs.yml — outside of it, the CLI will fail to find the configuration.
Local preview is only for development. In a real environment, the generated output is published to remote storage, and the TechDocs backend pulls it from there every time a user opens a documentation page. The three most common providers are S3, Google Cloud Storage, and Azure Blob Storage.
| Aspect | Local Preview | Cloud Storage (S3 / GCS / Azure Blob) |
|---|---|---|
| Output location | A local folder on the machine | Centralized object store |
| Who sees it | Only the developer on this machine | All Backstage users |
| Persistence | Gone when the folder is deleted | Stored, versioned per build |
| Trigger | Manual @techdocs/cli serve | @techdocs/cli publish from CI |
Cloud storage is connected through the techdocs.publisher configuration in app-config.yaml. The techdocs.publisher.type value determines the provider: awsS3 for S3, googleGcs for Google Cloud Storage, and azureBlobStorage for Azure Blob. Each type has its own bucket or container settings.
techdocs:
builder: 'external'
publisher:
type: 'awsS3'
awsS3:
bucketName: 'backstage-techdocs'
region: 'ap-southeast-1'
s3ForcePathStyle: falseThe value builder: 'external' indicates that the build isn't done by the TechDocs backend but by CI — the result is then published to S3. This is the most common production pattern: CI builds the documentation on every merge, then uploads the result.
Once the backend is pointed at a provider, the publish command sends the build output to storage. From CI, this command runs with provider-appropriate parameters:
npx @techdocs/cli publish --publisher-type awsS3 --storage-name backstage-techdocsWith this pattern, the docs-as-code flow closes the loop: developers write Markdown in docs/, pull requests are reviewed, CI runs generate then publish, and the TechDocs page in Backstage immediately shows the latest version.
Important
Keep versions in sync: the documentation shown in TechDocs is the documentation that was published. If CI doesn't run generate and publish, the page will keep showing the old build even after docs/ in the repository changed. Make TechDocs publishing part of the pipeline, not a manual task.
In this episode 7, you brought documentation to life with TechDocs: the docs-as-code concept, the MkDocs generator with the techdocs-core plugin, mkdocs.yml configuration, the docs/ folder structure, the backstage.io/techdocs-ref annotation on entities, the generate and publish commands from @techdocs/cli, and the difference between local preview and cloud storage like S3, GCS, and Azure Blob.
The key takeaways:
techdocs-core is the only plugin you really need — it brings most of the MkDocs features TechDocs requires.backstage.io/techdocs-ref, TechDocs doesn't know where to find an entity's documentation.In the next episode, episode 8, we lock Backstage's front door: Authentication & Identity — how Backstage recognizes users, connects various login providers like GitHub, Google, OIDC, and SAML, and how that identity flows all the way to the backend.