Developer Portals and Documentation Platforms: IDPs vs Good Docs
Developer Portals and Documentation Platforms: IDPs vs Good Docs
There is a pattern that repeats across growing engineering organizations. Developers cannot find documentation. They do not know which team owns a service. They cannot figure out how to deploy something. The instinct is to buy or build a developer portal. But the root problem is usually one of two things: either you genuinely need a service catalog and self-service platform, or you just need documentation that does not suck.
These are different problems with different solutions. An Internal Developer Portal (IDP) like Backstage is a service catalog, scaffolding system, and plugin ecosystem rolled into one. A documentation platform like Docusaurus is a static site generator optimized for technical writing. Confusing the two leads to either over-engineering (building a portal when you need docs) or under-engineering (writing docs when you need a catalog).
This guide covers both categories honestly.
Internal Developer Portals
Internal developer portals centralize information about your services, infrastructure, teams, and processes. The good ones also let developers self-serve -- creating new services, provisioning infrastructure, running workflows -- without filing tickets.
Backstage (Spotify)
Backstage is the open-source developer portal that Spotify built and donated to the CNCF. It has become the default choice for companies building an IDP, partly because of its feature set and partly because there is no real open-source alternative at its scale.
Core Concepts:
- Software Catalog: A registry of all services, libraries, APIs, and infrastructure components
- Software Templates: Scaffolding system for creating new services with best practices baked in
- TechDocs: Documentation-as-code, rendered from Markdown files in each repo
- Plugins: Extensibility layer for integrating CI/CD, monitoring, cloud providers, etc.
# catalog-info.yaml -- lives in each repo
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: user-service
description: Handles user authentication and profile management
annotations:
github.com/project-slug: myorg/user-service
backstage.io/techdocs-ref: dir:.
pagerduty.com/service-id: P1234XY
tags:
- typescript
- grpc
spec:
type: service
lifecycle: production
owner: team-platform
system: user-management
providesApis:
- user-api
consumesApis:
- notification-api
dependsOn:
- resource:user-database
Software Templates (scaffolding):
# template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: typescript-service
title: TypeScript Microservice
description: Creates a new TypeScript service with CI/CD, monitoring, and database
spec:
owner: team-platform
type: service
parameters:
- title: Service Details
required: [name, owner]
properties:
name:
title: Service Name
type: string
pattern: '^[a-z][a-z0-9-]*$'
owner:
title: Owner Team
type: string
ui:field: OwnerPicker
database:
title: Database Type
type: string
enum: [postgres, mysql, none]
default: postgres
steps:
- id: fetch
name: Fetch Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
- id: publish
name: Create Repository
action: publish:github
input:
repoUrl: github.com?owner=myorg&repo=${{ parameters.name }}
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
Honest Assessment:
Backstage is powerful but expensive to operate. It requires dedicated engineering effort -- someone needs to maintain the Backstage instance, build plugins, keep catalog data current, and manage the infrastructure. Spotify has a team of 40+ people working on their internal Backstage instance. You will not need that many, but "deploy Backstage and forget about it" is not realistic.
The plugin ecosystem is broad but uneven. Some plugins are well-maintained (GitHub, PagerDuty, Kubernetes), others are abandoned community contributions. Expect to write custom plugins.
Best for: Companies with 100+ developers, multiple teams, and the engineering capacity to maintain a platform.
Port
Port is a SaaS developer portal that positions itself as "Backstage without the maintenance." You define your data model, ingest data from your existing tools, and get a portal with self-service actions.
# Port blueprint (defines a service entity)
{
"identifier": "microservice",
"title": "Microservice",
"schema": {
"properties": {
"language": { "type": "string", "enum": ["TypeScript", "Go", "Python"] },
"tier": { "type": "string", "enum": ["critical", "standard", "internal"] },
"on_call": { "type": "string" },
"grafana_url": { "type": "string", "format": "url" },
"last_deploy": { "type": "string", "format": "date-time" }
}
},
"relations": {
"team": { "target": "team", "required": true },
"api": { "target": "api", "many": true }
}
}
Port's advantage is speed to value. You can have a working portal in days, not months. The trade-off is flexibility -- you are working within Port's framework rather than building your own.
Best for: Companies that want a portal but do not want to maintain Backstage. 50-500 developers.
Cortex and OpsLevel
Cortex and OpsLevel are SaaS portals that emphasize service maturity and engineering standards. They automatically score services based on criteria you define -- Does it have CI/CD? Is it using the approved database? Does it have documentation?
# Cortex scorecard example
scorecards:
- name: Production Readiness
rules:
- title: Has CI/CD pipeline
expression: github.workflows.length > 0
weight: 20
- title: Has on-call rotation
expression: pagerduty.service != null
weight: 25
- title: Has README
expression: github.files.includes("README.md")
weight: 10
- title: Test coverage > 80%
expression: sonarqube.coverage > 80
weight: 25
- title: No critical vulnerabilities
expression: snyk.critical == 0
weight: 20
These scorecards are genuinely useful for engineering leadership. They give visibility into which services meet standards and which do not, without requiring manual audits.
Best for: Engineering orgs focused on reliability, compliance, or standardization. Particularly useful if you need to demonstrate compliance (SOC2, etc.).
When You Need an IDP
You need an internal developer portal when:
- Developers cannot find who owns a service. If answering "who owns this?" requires Slack archaeology, you need a catalog.
- Service creation involves filing tickets. If spinning up a new service takes days of manual setup, you need self-service scaffolding.
- You have more than 50 services. Below this threshold, a spreadsheet or wiki page works fine.
- You are doing platform engineering. If you have a platform team building golden paths, an IDP is where those paths live.
You do not need an IDP when:
- You have fewer than 30 developers. Everyone already knows who owns what.
- Your problem is documentation, not discovery. An IDP will not fix bad docs -- it will just give you a new place to put bad docs.
- Nobody will maintain it. An unmaintained developer portal with stale data is worse than no portal at all.
Documentation Platforms
If your actual problem is "developers cannot find how to do things," you need better documentation, not a portal. Here are the tools worth considering.
Docusaurus
Docusaurus (by Meta) is the most popular open-source documentation framework. It generates a static site from Markdown/MDX files with versioning, search, i18n, and a plugin system.
npx create-docusaurus@latest my-docs classic --typescript
docs/
├── intro.md
├── getting-started/
│ ├── installation.md
│ └── configuration.md
├── guides/
│ ├── authentication.md
│ └── deployment.md
└── api/
└── reference.md
// docusaurus.config.js
const config = {
title: 'My Platform Docs',
url: 'https://docs.example.com',
baseUrl: '/',
organizationName: 'myorg',
projectName: 'docs',
presets: [
[
'classic',
{
docs: {
sidebarPath: './sidebars.js',
editUrl: 'https://github.com/myorg/docs/edit/main/',
showLastUpdateTime: true,
showLastUpdateAuthor: true,
versions: {
current: { label: 'v3.x', path: 'next' },
},
},
blog: {
showReadingTime: true,
blogTitle: 'Engineering Blog',
},
},
],
],
themes: [
[
require.resolve('@easyops-cn/docusaurus-search-local'),
{ hashed: true },
],
],
};
Pros: Battle-tested, excellent versioning for API docs, strong community, self-hosted. MDX support means you can embed interactive components in docs.
Cons: React-based, which means build times get slow with 1,000+ pages. The default theme looks like every other Docusaurus site. Customization beyond the basics requires understanding the React internals.
Nextra
Nextra is a Next.js-based documentation framework. It is lighter than Docusaurus and feels more natural if your team already uses Next.js.
npx create-next-app my-docs --example https://github.com/shuding/nextra-docs-template
pages/
├── _meta.json # Sidebar configuration
├── index.mdx
├── getting-started.mdx
└── guides/
├── _meta.json
├── auth.mdx
└── deploy.mdx
// pages/_meta.json
{
"index": "Introduction",
"getting-started": "Getting Started",
"guides": "Guides",
"api": "API Reference"
}
---
title: Authentication Guide
---
import { Callout, Tabs, Tab } from 'nextra/components'
# Authentication
<Callout type="warning">
Always use HTTPS in production. HTTP auth tokens can be intercepted.
</Callout>
<Tabs items={['JWT', 'Session', 'OAuth']}>
<Tab>
```typescript
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '24h',
});
```
</Tab>
<Tab>
Session-based auth stores state server-side...
</Tab>
</Tabs>
Pros: Fast, built on Next.js (ISR, API routes, React Server Components), clean default theme, great MDX support. Lighter than Docusaurus.
Cons: Smaller community, fewer plugins, no built-in versioning. If you need doc versioning, you will build it yourself.
Mintlify
Mintlify is a SaaS documentation platform that generates beautiful docs from Markdown files in your repo. You push to git, Mintlify builds and hosts.
# mint.json
{
"name": "My API",
"logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg" },
"favicon": "/favicon.svg",
"colors": { "primary": "#0D6EFD", "light": "#4A9EFF", "dark": "#0050C8" },
"navigation": [
{
"group": "Getting Started",
"pages": ["introduction", "quickstart", "authentication"]
},
{
"group": "API Reference",
"pages": [
"api-reference/users/list",
"api-reference/users/create",
"api-reference/users/get"
]
}
],
"api": {
"baseUrl": "https://api.example.com",
"auth": { "method": "bearer" }
},
"openapi": "openapi.yaml"
}
Mintlify auto-generates interactive API reference pages from your OpenAPI spec, complete with "Try It" buttons. The output looks polished -- noticeably better than default Docusaurus or Nextra.
Pros: Beautiful out of the box, interactive API playground, built-in analytics, auto-generated API docs from OpenAPI specs.
Cons: SaaS-only (no self-hosting), pricing scales with pages and features. You are dependent on Mintlify staying in business. Limited customization compared to building your own with Docusaurus.
ReadMe
ReadMe is a full-featured API documentation platform. It does more than static docs -- it captures API usage metrics, shows personalized code samples (using the reader's actual API key), and provides interactive "Try It" consoles.
# .readme.yml
version: 2
apis:
- id: main-api
source: openapi.yaml
slugPrefix: api
Pros: Personalized docs (users see their own API keys in examples), API metrics dashboard, excellent interactive experience. If your product is an API, ReadMe makes your docs part of the developer experience.
Cons: Expensive. Pricing starts reasonable but scales up quickly. The editing experience is browser-based, not files-in-git. Vendor lock-in is significant -- migrating off ReadMe means rebuilding your docs from scratch.
Comparison Summary
| Feature | Docusaurus | Nextra | Mintlify | ReadMe |
|---|---|---|---|---|
| Hosting | Self-hosted | Self-hosted | SaaS | SaaS |
| Source format | Markdown/MDX | MDX | Markdown | Web editor + OpenAPI |
| Versioning | Built-in | Manual | Planned | Built-in |
| API playground | Plugin needed | No | Built-in | Built-in |
| Search | Plugin (Algolia/local) | Built-in | Built-in | Built-in |
| Price | Free | Free | $150+/mo (teams) | $99+/mo |
| Best for | Large doc sites | Next.js teams | API docs | API-first products |
IDP vs Docs: Making the Decision
Here is a decision tree:
"Developers cannot find documentation" --> Fix your docs. Use Docusaurus or Nextra. Reorganize content. Add search. This is a content problem, not a tooling problem.
"Developers do not know who owns what" --> Start with a service catalog. Backstage's catalog or Port can solve this without building a full IDP.
"Creating a new service takes too long" --> You need scaffolding/self-service. This is IDP territory -- Backstage templates, Port self-service actions, or even just good CLI tools.
"We need to track engineering standards" --> Cortex or OpsLevel scorecards. Or Backstage with the Tech Insights plugin.
"We need all of the above" --> You probably need an IDP. But start with the catalog and add capabilities incrementally. Do not try to ship everything at once.
The Hybrid Approach
Many successful organizations use both. The IDP handles service discovery, scaffolding, and operational concerns. The docs platform handles guides, tutorials, and API references. The IDP links out to the docs.
# catalog-info.yaml -- linking to external docs
metadata:
annotations:
backstage.io/techdocs-ref: dir:.
links:
- url: https://docs.example.com/guides/user-service
title: User Service Guide
- url: https://api.example.com/docs
title: API Reference
Bottom Line
For documentation: Start with Docusaurus if you want maximum control and a battle-tested platform. Use Nextra if you are a Next.js shop and want something lighter. Use Mintlify if you want beautiful API docs without building anything. Use ReadMe only if your product is an API and you want personalized, metrics-driven docs.
For developer portals: Use Backstage if you have the engineering capacity to maintain it (realistically, at least one dedicated engineer). Use Port if you want the same capabilities without the maintenance. Use Cortex or OpsLevel if your primary concern is engineering standards and service maturity.
The most common mistake is building a developer portal when the real problem is documentation. A portal does not help if the information it links to does not exist or is outdated. Fix your docs first, then consider whether you need a catalog, scaffolding, or self-service capabilities on top.
Start with the smallest tool that solves your actual problem. You can always add more tooling later, but removing an underused portal that took six months to build is painful.