InsightsPlatform Engineering
Golden paths are an interface, not a template
Why the most important design decision in an internal developer platform is what developers declare, and what the platform decides for them.
Published October 13, 20263 min read
Internal developer platforms tend to be judged by their features: how many resource types they provision, and how many integrations they offer. Adoption depends on something else. It depends on how small and stable the interface is that a product team has to learn.
The interface is the product
A golden path is a supported way to do something common, such as creating a service, adding a database or exposing an endpoint. Teams follow it because it is easier than the alternative, not because they are told to.
That only works if the input is small. Compare what a developer has to write in two approaches. First, raw Kubernetes and cloud resources:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders
spec:
replicas: 3
template:
spec:
containers:
- name: orders
image: registry.internal/checkout/orders:1.4.2
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { memory: 512Mi }
readinessProbe:
httpGet: { path: /healthz, port: 8080 }
# ...plus Service, Ingress, HPA, PodDisruptionBudget,
# NetworkPolicy, ServiceMonitor, IAM role, database...Second, a platform interface:
apiVersion: platform/v1
kind: Service
name: orders
team: checkout
runtime: http
size: small
expose: internal
dependencies:
- postgres: orders-dbThe second file is shorter, but not because detail was hidden carelessly. The platform team made those decisions once, for everyone, and encoded them.
Decide what is a choice
For every field in the interface, ask whether product teams really need to choose it:
- Resource limits: usually not. Offer a few sizes and adjust them from metrics.
- Probes, budgets, network policy: not a choice. Derive them.
- Exposure: yes, but from a short list.
- Dependencies: yes. This is where teams express intent.
What the platform derives
Each field in the interface expands into concrete resources the team never writes by hand:
| Field | What the platform generates |
|---|---|
size: small | CPU and memory requests and limits, autoscaling bounds, a disruption budget |
runtime: http | Deployment, Service, probes on the standard health endpoint, metrics scraping |
expose: internal | Internal route, TLS certificate, network policy that admits only in-cluster callers |
dependencies | The database, a workload identity allowed to reach it, credentials mounted as a secret |
team | Ownership labels, alert routing, cost allocation tags |
Every row is a decision that would otherwise be made by every team, each slightly differently. This is where the platform earns its keep.
Start with one complete journey
A common failure is to start with a catalogue of twenty templates, each half-finished. Start instead with the journey most teams repeat, usually "create a new HTTP service and get it to production". Make that journey complete from one request: repository, pipeline, environments, observability and on-call routing.
One path that works end to end earns more trust than ten that stop at the cluster. After that, follow demand: support requests and workarounds show which journey to pave next.
Keep the interface stable
Once teams depend on the interface, changing it is expensive. Version it (the apiVersion field above exists for this). Keep old versions working while teams migrate, and treat breaking changes with the same care as a public API.
Changes underneath the interface, such as a new ingress controller or a different secret store, should not require any change from product teams. That is how you know the abstraction is in the right place.
Measure adoption, not features
Useful signals:
- The share of new services created through the golden path.
- Time from creating a repository to the first production deploy.
- Support requests per service per month.
- The number of services running on the current interface version.
Features that do not move these numbers are probably not the bottleneck.