How to Build an Internal Developer Platform: Start With One Developer Journey
Your platform roadmap has a portal, a service catalog, templates, policy engines, scorecards, and three infrastructure APIs. Six months later, a developer creating payments-api still opens four tickets and messages the one engineer who knows how production access works. You built platform components. You did not build a usable platform.
I would stop the component roadmap and pick one developer journey that must work from start to finish. Not a demo. Not a repository generator that hands the hard parts back to the user. One production-ready path that removes a repeated source of waiting for a real product team.
That is how I would build the first increment of an internal developer platform.
Choose a journey worth turning into a product
Section titled “Choose a journey worth turning into a product”Start with a task developers repeat across several teams and dislike for the same reasons. New-service creation is a strong candidate when every product group has to assemble a repository, pipeline, runtime, identity, controls, telemetry, and ownership metadata by hand.
It is not always the right first journey.
The most critical service is usually a poor first customer. So is the most unusual workload. Both attract exceptions, senior attention, and non-functional requirements that can turn a thin slice into a year-long foundation program. Google Cloud’s guidance on starting a minimum viable platform with a smaller user group makes the same point: build depth for a bounded population before you expand the surface.
I use four filters to select the first journey:
| Filter | Evidence to bring |
|---|---|
| Repeated friction | Several teams follow near-identical steps or wait on the same handoffs |
| Measurable cost | You can observe elapsed time, waiting, failures, or direct support effort |
| Manageable risk | The path can reach production without starting from the hardest regulatory or scale case |
| Partner demand | One product team is willing to build, test, and operate through the path with you |
For payments-api, assume the current journey takes nine working days. The product team opens tickets for a cloud namespace, workload identity, pipeline approval, secrets, and production access. Two tickets ask for information that already exists in the service catalog. A senior platform engineer spends six hours coordinating the handoffs.
Write that baseline as a journey record, not a complaint:
| Baseline signal | Current observation |
|---|---|
| Elapsed time | Nine working days from approved request to first production deployment |
| Waiting | Six days across four queues |
| Direct support | Six hours from a senior platform engineer |
| First-pass success | Two of the last five services completed without rework |
| Hidden knowledge | Production access depends on one named specialist |
That is a platform candidate because the problem is repeated integration work, not one missing tool. The record also prevents you from declaring victory when a new portal shortens request entry but leaves the six days of waiting untouched.
A small organization with three services and no repeated coordination cost may not need an IDPInternal Developer PlatformA self-service layer of shared tools, services, documentation, and delivery paths designed for an organization’s software developers. at all. Improve the existing path directly. A platform product only earns its operating cost when several teams benefit from the same contract.
Write the journey contract before choosing the interface
Section titled “Write the journey contract before choosing the interface”Do not start with Backstage, a CLI, or an API. Start with the result the user needs and the boundary the platform will own.
For the worked journey, the user provides a service name, owning team, runtime profile, data classification, and target environment. The platform returns a repository with ownership metadata, a tested delivery pipeline, workload identity, runtime allocation, baseline controls, telemetry, documentation, and a deployed first version.
That sentence is the product contract.
Make it testable before implementation:
| Contract area | Decision to record |
|---|---|
| Inputs | What is the smallest valid request, and which data can the platform derive? |
| Output | What assets, access, documentation, and operational evidence does the user receive? |
| Completion | What proves the service has reached the first production deployment? |
| Manual checkpoints | Which human decisions remain, who owns them, and how are they observed? |
| Failure and support | How does the user see progress, recover, clean up, or get help? |
Self-service does not mean that no human decision exists. A security reviewer may still approve a high-risk data classification. A production owner may still accept a new external dependency. The test is whether those checkpoints are explicit and bounded, rather than discovered through a Slack message halfway through the journey.
Define completion from the user’s perspective. “Repository created” is not completion when the user still has to discover how to obtain an identity, connect secrets, register ownership, and reach production. For this journey, completion means a first version is running, the team can observe it, the ownership record exists, and the user knows how to change or remove what the platform created.
Capture the baseline at the same time. Count elapsed time, waiting time, tickets, failed attempts, and direct interventions. You need the before-state because a polished interface can hide the same old dependency behind a button.
The CNCF Platforms White Paper recommends platform capabilities arranged around user needs, delivered as a product, and measured through signals such as request-to-fulfillment latency and time to deploy a new service. That evidence matters more than the number of templates you ship.
Build the thinnest production-ready slice
Section titled “Build the thinnest production-ready slice”Thin does not mean incomplete. Production-ready does not mean that you automate every future variant.
Your first slice needs enough capability for one team to trust the journey on a real service. I separate it into four layers:
| Layer | Minimum responsibility |
|---|---|
| Experience | Collect valid input and show progress, results, failures, and the support route |
| Orchestration | Coordinate deterministic steps, approvals, retries, cleanup, and evidence |
| Capability providers | Reuse source control, CI/CD, cloud, identity, secrets, policy, and observability systems |
| Product record | Store ownership, lifecycle, documentation, usage, operational evidence, and feedback |
The platform layer should compose existing providers rather than replace them. Your source-control system already creates repositories. Your cloud platform already allocates identities and runtime resources. Your observability stack already creates dashboards and alerts. The IDP gives the user a coherent contract across those systems.
If cloud foundations are still the constraint, build a progressive landing zone around the next workload rather than waiting for a complete enterprise foundation before the journey can run.
For payments-api, the orchestration might create the repository, register team-payments as owner, provision payments-api-prod with workload identity, attach the approved pipeline, apply the baseline policy bundle, create service indicators, and deploy version 0.1.0. Each step returns evidence into the product record. If step six fails, the user sees what succeeded, what will be cleaned up, and who owns the next action.
A portal can be the experience layer. It is not the architecture.
Backstage Software Templates illustrate a useful orchestration pattern: collect parameters, execute ordered actions, publish a repository, register metadata, and expose execution logs. You can implement the same contract through a CLI, pull request, service API, or a combination. Choose the interface that fits the users and the journey.
I have seen teams call a template production-ready because it creates a repository and passes the first build. Then the new service has no owner in the catalog, no production dashboard, no upgrade path for the template, and no clear recovery when provisioning fails after creating half the resources.
The slice is not done.
Day-two work belongs in the first acceptance contract. Decide how policy and pipeline updates reach existing services. Record which generated files a product team may change and which stay managed. Define how a team leaves the path without leaving orphaned cloud resources or undocumented controls behind. You do not need a universal lifecycle engine, but you do need an answer for the service you are putting into production.
For payments-api, production-ready means the first deployment can be operated the next morning. Ownership is visible. Logs and service indicators exist. The team knows how to roll back. Failed provisioning can be retried or cleaned up. The generated path has documentation and a support boundary. Baseline security controls are applied, even when some higher-risk decisions still require a named approval.
This is also where scope discipline matters. Do not build a generic workflow engine because the journey needs three retries. Do not create a universal policy language because this service needs two controls. Preserve clear interfaces where later variation is likely, but let evidence earn the abstraction.
Run the whole path with one partner team
Section titled “Run the whole path with one partner team”A successful demo proves that the builders know the happy path. It does not prove that another team can use the product.
Take one partner team through the full payments-api journey. Watch what they do instead of asking only whether they liked it. Record where they leave the platform, which fields they do not understand, when they ask for help, and what happens after a partial failure.
The partner team is not a passive beta group. It shares the real deadline, operational constraints, and failure evidence. In return, the platform team stays close enough to observe the work without silently completing it behind the scenes. Every intervention is logged. Otherwise, you can report a successful self-service journey that was actually delivered by two platform engineers on a private channel.
The Spotify account of 1,186 days with Backstage describes an integrated journey that reaches far beyond scaffolding: environment setup, project creation, build, publication, monitoring, repository creation, resource allocation, catalog registration, deployment configuration, and connections to internal systems. That is the useful reference point. The value comes from connecting the steps, not displaying them in one portal.
Measure the whole path:
| Signal | What it tells you |
|---|---|
| End-to-end elapsed time | Whether the developer reaches a usable result sooner |
| Waiting time | Whether organizational dependencies remain hidden |
| Task success | Whether the user completes the journey without direct platform-team action |
| Intervention rate | Whether the path is self-service or manually assisted behind the scenes |
| Delivery stability | Whether faster provisioning creates failures, risky changes, or recovery work |
Add developer confidence as qualitative evidence: does the user understand what was created, who owns it, and how to operate it? The related developer-experience measurement method can help you combine that reported experience with journey telemetry.
Do not optimize for adoption alone. The DORA 2024 report associates internal developer platforms with better individual, team, and organizational performance, but also reports lower change stability and throughput in its sample. That does not prove the platform caused the decline. It does prove that login counts and template executions are not enough.
Compare the first production runs with the baseline. A credible result might be two working days instead of nine, one bounded approval instead of four queues, no direct platform action in four of five runs, and no deterioration in deployment failures or recovery time. Keep the raw journey record. A median can improve while one recurring failure still makes the path unusable for a class of services.
If payments-api reaches production in two days instead of nine but the generated pipeline creates larger, riskier changes, you moved the bottleneck. Fix the delivery path before scaling it.
Let evidence choose the next increment
Section titled “Let evidence choose the next increment”A capability roadmap makes expansion feel automatic. The portal shipped, so the catalog comes next. The catalog shipped, so scorecards follow. That sequence may be tidy and still solve nothing.
Use the evidence from the first journey to choose the next move.
| Evidence after the first runs | Next investment |
|---|---|
| Intervention remains high | Simplify inputs, errors, support, or orchestration in the same journey |
| One provider causes most failures | Repair that provider contract before adding features |
| Reuse is voluntary and stable | Open the journey to another product group |
| A different repeated wait now dominates | Design a second journey around that constraint |
| Benefit remains local to one team | Stop platform expansion and let the team own the solution |
If developers still need a platform engineer in half the runs, deepen the current path. If failures cluster around identity provisioning, fix that provider contract. If three teams reuse the journey successfully, expand the population. If a different repeated problem now dominates waiting time, start a second journey. If the gain applies only to one team, stop calling it a shared platform capability.
The CNCFCloud Native Computing FoundationA Linux Foundation project that hosts and governs open-source technologies for cloud-native software infrastructure. Platform Engineering Maturity Model distinguishes extrinsic push from intrinsic pull. Push is usage created by a mandate. Pull is when teams return because the platform gives them a better way to work. The second signal is stronger.
You may still mandate controls in a regulated environment. Usability is not optional there either. A required path that creates hidden queues will be bypassed, delayed, or worked around. Make the common compliant path faster, show exceptions clearly, and retain evidence of the decisions.
Microsoft’s platform engineering capability model also treats investment, adoption, governance, provisioning, interfaces, and measurement as separate capabilities. You do not need to mature all of them at once. You need enough of each to make the chosen journey trustworthy.
The result may look less impressive than a broad platform launch. That is healthy. One narrow path that product teams trust gives you a base for reusable contracts, common telemetry, and a real backlog of demand. A wide platform with no completed journey gives you component ownership debates and migration plans before you have proved that the product improves work.
Pick one repeated journey this week. Map it from request to production, including every wait state and manual decision. Write the acceptance contract on one page. Then build only the capabilities required for one partner team to complete that path and operate the result. Do not add a second journey until the first one has removed measurable friction without moving the risk somewhere else.
Article series
Platform Engineering: From Friction to First Journey
Explore every resource in this series, whatever its format.