A few years ago, I watched a talented backend engineer spend most of a sprint trying to deploy a simple Go service. The code was finished on day two. The rest of the time went into figuring out which Helm chart to copy, which Terraform module was "the current one," why the CI pipeline needed a secret nobody could find, and which Slack channel owned the ingress controller.
None of that work made the product better. It was pure friction.
That story is not unusual. It is, in fact, the story that pushed Platform Engineering from a conference buzzword into a real discipline with its own job titles, budgets, and career paths. In 2026, most mid-to-large engineering organizations either have a platform team or are actively building one, and the most visible output of that team is usually an Internal Developer Portal (IDP).
In this deep dive, we'll look at why "you build it, you run it" started breaking down, what Platform Engineering actually is, how to design golden paths that developers genuinely want to use, and how to keep all of it secure under a zero-trust model. There's real code, real architecture, and the mistakes I've seen teams make along the way.

Why DevOps Hit a Wall
Let's be clear: DevOps didn't fail. It won. Breaking down the wall between development and operations was one of the best things to happen to software delivery.
The problem is what came next. As cloud-native adoption exploded, the "ops" half of a developer's job grew enormously. A typical product engineer in a modern company might be expected to understand:
- Kubernetes manifests, Helm, or Kustomize
- Terraform, Pulumi, or Crossplane for infrastructure
- GitHub Actions, GitLab CI, or Argo Workflows
- Service mesh configuration and mTLS
- OpenTelemetry instrumentation and dashboards
- Secrets management through Vault or a cloud KMS
- SBOMs, image signing, and vulnerability scanning
- Cost tagging, autoscaling policies, and network policies
That's not "DevOps." That's asking every developer to also be a part-time SRE, security engineer, and FinOps analyst. Industry surveys over the past few years have consistently pointed at the same thing: cognitive load is one of the biggest drags on developer productivity.
The "Shift Left" Overcorrection
"Shift left" was meant to catch problems earlier. In practice, many organizations shifted responsibility left without shifting support along with it. Security, compliance, and operations tasks landed on developers' desks with a wiki page and a good-luck wave.
The result was predictable:
- Snowflake services — every team set things up slightly differently
- Ticket queues — anything non-standard required waiting on an ops team
- Tribal knowledge — the "right way" lived in a few senior engineers' heads
- Security drift — controls were applied inconsistently, if at all
Platform Engineering is the answer to this overcorrection. Rather than pushing everything onto developers, it builds a layer that absorbs the complexity and exposes a simpler, self-service interface.
What Platform Engineering Actually Is
The simplest definition I use:
Platform Engineering is the practice of building and running an internal platform as a product, so that application teams can self-serve the infrastructure and tooling they need, safely and quickly.
Three ideas in that sentence matter most.
- Platform as a product. The platform has users (developers), a roadmap, a feedback loop, and success metrics. It is not just a pile of scripts.
- Self-service. Developers shouldn't need to file a ticket to get a database, a new environment, or a deployment pipeline.
- Safely. Guardrails are built in, not bolted on. The easy path is also the compliant path.
This connects closely to the Team Topologies model, where a platform team exists to reduce the cognitive load of stream-aligned teams (the teams building customer-facing features).
Internal Developer Platform vs. Internal Developer Portal
These two terms get mixed up constantly, and the confusion causes real planning mistakes.
| Concept | What it is | Examples |
|---|---|---|
| Internal Developer Platform | The full set of capabilities and integrations behind the scenes | CI/CD, Kubernetes clusters, IaC modules, secrets, observability, policy engines |
| Internal Developer Portal | The user interface developers interact with | Backstage, Port, Cortex, Roadie, a custom web UI |
Think of it this way: the platform is the kitchen, and the portal is the menu. A beautiful menu with a broken kitchen still leaves people hungry. Many teams launch a portal first, populate a service catalog, and then wonder why adoption stalls. It's because the portal had nothing powerful behind it.
The Architecture at a Glance
Here's how the pieces typically fit together in a 2026 platform:
flowchart TB
Dev[Developer] --> Portal[Internal Developer Portal]
Dev --> CLI[Platform CLI]
subgraph Interface Layer
Portal
CLI
end
Portal --> Catalog[Software Catalog]
Portal --> Templates[Golden Path Templates]
Portal --> Docs[TechDocs and Scorecards]
Templates --> Orchestrator[Platform Orchestrator]
CLI --> Orchestrator
subgraph Control Plane
Orchestrator --> GitOps[GitOps - Argo CD or Flux]
Orchestrator --> IaC[Crossplane or Terraform]
Orchestrator --> Policy[Policy Engine - OPA or Kyverno]
end
subgraph Resource Plane
GitOps --> K8s[Kubernetes Clusters]
IaC --> Cloud[Cloud Resources - DBs, Queues, Buckets]
end
subgraph Cross-Cutting
Sec[Identity, Secrets, mTLS]
Obs[OpenTelemetry Observability]
end
K8s --- Sec
K8s --- Obs
Cloud --- Sec
The key insight: developers mostly interact with the top layer. The platform team owns the layers underneath and evolves them without forcing every product team to relearn everything.
Golden Paths: The Heart of the Platform
If the portal is the front door, golden paths are the hallways that actually take people somewhere useful.
A golden path is an opinionated, well-supported, end-to-end way of doing a common task. Spotify popularized the term, and it has become the standard vocabulary for this idea. Examples include:
- "Create a new Go microservice with a Postgres database"
- "Spin up a preview environment for a pull request"
- "Add a Kafka topic with the right retention and ACLs"
- "Onboard a new team with repos, permissions, and dashboards"
What Makes a Good Golden Path
From what I've seen, the paths that get adopted share four traits:
- Paved, not walled. Developers can step off the path if they have a real reason. The path is the default, not a prison.
- End-to-end. It doesn't stop at "here's a repo." It goes all the way to a running, observable, secure service in production.
- Maintained. The platform team owns updates. When a base image gets patched, every service on the path benefits.
- Fast. If following the golden path is slower than hacking something together, people won't use it.
Real-World Example: A Fintech's 40-Minute Service
Here's a composite example based on patterns I've seen in several organizations.
A mid-sized fintech company had roughly 25 product teams. Spinning up a new service took about two to three weeks, mostly spent waiting on tickets for databases, DNS, secrets, and security reviews.
The platform team made three moves:
- Built a "Standard Service" golden path in Backstage that generated a repo, CI pipeline, Kubernetes manifests, and a Crossplane claim for a managed Postgres instance.
- Pre-approved the template with the security team, so services created from it didn't need a separate review.
- Added scorecards so teams could see how their existing services compared to the golden path standard.
Within two quarters, new services went from weeks to under an hour. More interesting, though, was the side effect: older services started migrating onto the golden path voluntarily, because being on the path meant free upgrades and fewer audit headaches.
That is the signal you're looking for. Voluntary adoption is the best metric a platform team has.

Building an IDP: Hands-On Code
Let's get practical. Below is a simplified but realistic setup using Backstage for the portal, Crossplane for infrastructure, Argo CD for GitOps, and Kyverno for policy. You can swap any of these for equivalents; the patterns are what matter.
Step 1: Register Services in the Software Catalog
Everything in an IDP starts with the catalog. Each service declares itself with a catalog-info.yaml in its repo:
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payments-api
description: Handles card authorization and settlement
annotations:
github.com/project-slug: acme/payments-api
argocd/app-name: payments-api-prod
backstage.io/techdocs-ref: dir:.
tags:
- go
- pci
links:
- url: https://grafana.acme.internal/d/payments
title: Service Dashboard
spec:
type: service
lifecycle: production
owner: group:payments-team
system: checkout
providesApis:
- payments-api-v2
dependsOn:
- resource:payments-postgresA clean catalog answers the questions that used to require Slack archaeology: Who owns this? Where are the docs? What does it depend on? Is it in production?
Step 2: Define a Golden Path Template
Backstage's Software Templates (the Scaffolder) let you turn a golden path into a form developers fill out.
# templates/go-service/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: go-service-postgres
title: Go Service with Postgres
description: Production-ready Go microservice with managed Postgres, CI, and observability
tags:
- go
- recommended
spec:
owner: group:platform-team
type: service
parameters:
- title: Service details
required: [name, owner]
properties:
name:
title: Service name
type: string
pattern: '^[a-z][a-z0-9-]{2,30}$'
owner:
title: Owning team
type: string
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Infrastructure
properties:
dbSize:
title: Database size
type: string
enum: [small, medium, large]
default: small
dataClassification:
title: Data classification
type: string
enum: [public, internal, confidential, restricted]
default: internal
steps:
- id: fetch
name: Generate from skeleton
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
owner: ${{ parameters.owner }}
dbSize: ${{ parameters.dbSize }}
dataClassification: ${{ parameters.dataClassification }}
- id: publish
name: Create repository
action: publish:github
input:
repoUrl: github.com?owner=acme&repo=${{ parameters.name }}
defaultBranch: main
protectDefaultBranch: true
- id: register
name: Register in catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
output:
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}Notice the dataClassification field. That one input can drive network policies, encryption settings, and logging rules downstream. It's a small detail that makes security automatic instead of manual.
Step 3: Self-Service Infrastructure with Crossplane
Instead of developers writing Terraform for a database, the platform team publishes a Composite Resource Definition. Developers just "claim" what they need:
# Generated into the new repo at deploy/database.yaml
apiVersion: platform.acme.io/v1alpha1
kind: PostgresInstance
metadata:
name: payments-postgres
namespace: payments
spec:
parameters:
size: small
version: "16"
dataClassification: confidential
compositionSelector:
matchLabels:
provider: aws
tier: standard
writeConnectionSecretToRef:
name: payments-postgres-connBehind the scenes, the platform team's Composition handles encryption at rest, private subnets, backups, IAM roles, and tagging. The developer never sees that complexity, but every database is configured correctly.
Step 4: Enforce Guardrails with Policy-as-Code
Golden paths make the right thing easy. Policies make the wrong thing hard. Here's a Kyverno policy that blocks unsigned images and requires ownership labels:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: platform-baseline
spec:
validationFailureAction: Enforce
background: true
rules:
- name: require-owner-label
match:
any:
- resources:
kinds: [Deployment, StatefulSet]
validate:
message: "Every workload must declare an owner team label."
pattern:
metadata:
labels:
platform.acme.io/owner: "?*"
- name: verify-image-signature
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "registry.acme.io/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/acme/*"
issuer: "https://token.actions.githubusercontent.com"Because the golden path template already produces signed images and correct labels, developers on the path never hit these errors. Only off-path workloads do, which is exactly what you want.
Step 5: A Secure CI Pipeline Baked into the Template
The template's skeleton includes a reusable workflow, so every service gets the same supply chain controls:
# .github/workflows/ci.yaml (generated by template)
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
id-token: write # for keyless signing via OIDC
packages: write
jobs:
build:
uses: acme/platform-workflows/.github/workflows/go-service.yaml@v4
with:
service-name: payments-api
generate-sbom: true
sign-image: true
slsa-level: 3
secrets: inheritThe uses: line is the magic. When the platform team improves the central workflow and bumps the version, teams pick up the change through a simple, automated pull request.
Zero-Trust Security in a Platform World
Zero trust used to be an architecture diagram that lived in a security team's slide deck. In a mature platform, it becomes the default behavior of every service.
The core principle: never trust, always verify. No workload gets access just because it's "inside the network."
Here's how the request flow looks when zero trust is part of the platform:
sequenceDiagram
participant Dev as Developer
participant Portal as IDP
participant CI as CI Pipeline
participant Reg as Image Registry
participant K8s as Kubernetes
participant Svc as Service B
Dev->>Portal: Create service from golden path
Portal->>CI: Scaffold repo + pipeline
CI->>CI: Build, test, generate SBOM
CI->>Reg: Push image signed via OIDC identity
K8s->>Reg: Admission controller verifies signature
K8s->>K8s: Policy check for labels and classification
K8s->>Svc: Request over mTLS with workload identity
Svc->>Svc: Authorize based on SPIFFE ID and policy
Practical Zero-Trust Building Blocks
- Workload identity. Use SPIFFE/SPIRE or your cloud's native workload identity so services authenticate with short-lived, verifiable identities instead of static keys.
- mTLS everywhere. A service mesh (Istio ambient mode, Linkerd, or Cilium) can enforce encrypted, authenticated service-to-service traffic without changing application code.
- Short-lived credentials. CI pipelines should use OIDC federation to get cloud credentials, not long-lived access keys stored as secrets.
- Supply chain integrity. Sign images with Sigstore, generate SBOMs, and aim for SLSA provenance. Verify at admission time.
- Least privilege by template. The golden path generates scoped IAM roles and network policies based on the service's declared dependencies.
Here's a default-deny network policy that a template might generate, opening only the paths the service actually declared:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: payments-api
namespace: payments
spec:
podSelector:
matchLabels:
app: payments-api
policyTypes: [Ingress, Egress]
ingress:
- from:
- namespaceSelector:
matchLabels:
platform.acme.io/system: checkout
egress:
- to:
- podSelector:
matchLabels:
app: payments-postgres
ports:
- protocol: TCP
port: 5432The beauty of this approach is that security stops being a gate at the end of the process. It becomes a property of the starting point.
Measuring Platform Success
A platform without metrics is just an expensive opinion. The good news is that we have solid frameworks in 2026.
Delivery metrics (DORA):
- Deployment frequency
- Lead time for changes
- Change failure rate
- Time to restore service
Developer experience metrics (SPACE and DevEx frameworks):
- Developer satisfaction and perceived productivity
- Time spent waiting on other teams
- Cognitive load ratings from surveys
Platform-specific metrics:
- Percentage of services on a golden path
- Time to first deploy for a brand-new service
- Onboarding time until a new hire's first production merge
- Self-service actions per week versus tickets filed
- Scorecard compliance across the catalog
I'd encourage tracking a mix of quantitative and qualitative signals. A short quarterly survey asking "What is the most annoying part of shipping code here?" often reveals more than any dashboard.

Where AI Fits in 2026
It would be strange to write about developer platforms in 2026 without mentioning AI. Coding agents and AI assistants are now part of most developers' daily workflow, and that has an interesting consequence for platform teams.
AI agents are a new kind of platform user. An agent that scaffolds a service or opens a pull request benefits enormously from clear golden paths, a structured catalog, and well-defined APIs. The same things that reduce cognitive load for humans also make agents more reliable.
Some practical patterns I've seen work:
- Exposing portal actions and catalog data through well-documented APIs (and, increasingly, MCP servers) so agents can discover ownership, dependencies, and templates
- Letting agents use golden path templates rather than generating infrastructure code from scratch
- Applying the same policy-as-code guardrails to agent-generated changes as to human ones
The platform becomes the safety rail for automation. That's a strong argument for investing in it now.
Best Practices for Building Your IDP
Here's what consistently separates successful platform initiatives from abandoned ones.
Start With Pain, Not Tools
Interview developers before you write a line of YAML. Find the top three things slowing them down. Your first golden path should solve one of those, not showcase the coolest technology.
Build the Thinnest Viable Platform
Team Topologies calls this the "Thinnest Viable Platform." Begin with a catalog, one solid golden path, and basic docs. Expand based on demand, not speculation.
Treat the Platform as a Product
- Appoint a platform product manager (or someone wearing that hat)
- Publish a public roadmap
- Run user interviews and track feature requests
- Write release notes developers actually read
Keep Templates Upgradeable
Generated code drifts. Use shared reusable workflows, base images, Helm library charts, and versioned Crossplane compositions so updates flow downstream. Tools that can open automated upgrade pull requests across repos are worth their weight in gold.
Make Ownership Mandatory
Every catalog entity needs an owner. Unowned services become security and reliability risks. Enforce it with policy, as in the Kyverno example above.
Document Inside the Portal
Docs-as-code with TechDocs or similar keeps documentation next to the service, versioned with the code, and discoverable from one place.
Common Mistakes to Avoid
I've made a few of these myself, and I've watched others repeat them.
- Launching a portal with nothing behind it. A catalog alone gets a burst of curiosity and then silence. Ship at least one high-value golden path at launch.
- Building a golden cage. Forcing every team onto a single stack with no escape hatch creates resentment and shadow infrastructure. Allow off-path work with clear trade-offs.
- Ignoring the long tail. Golden paths cover common cases. You still need a clear, humane process for the unusual ones.
- Underestimating Backstage maintenance. Backstage is a framework, not a finished product. Self-hosting it means TypeScript, plugin upgrades, and ongoing care. Budget for it, or consider a managed option.
- Measuring outputs instead of outcomes. "We built 14 templates" means nothing if nobody uses them. Measure adoption and developer time saved.
- Leaving security for later. Retrofitting signing, policies, and identity into hundreds of services is painful. Bake them into templates from the start.
- Turning the platform team into the new ops ticket queue. If developers still need to ask the platform team for everything, you've just renamed the bottleneck.
🚀 Pro Tips
- Run "golden path office hours." A weekly 30-minute drop-in session builds trust fast and surfaces friction you'd never find in a survey.
- Use scorecards as carrots, not sticks. Show teams what "good" looks like and celebrate improvements instead of shaming laggards.
- Measure time to "hello production." Have a new engineer create a service from scratch every quarter and time it. It's the most honest benchmark you have.
- Version everything the platform publishes. Templates, workflows, compositions, and policies should all have semantic versions and changelogs.
- Put cost visibility in the portal. Showing each team the monthly cost of their services next to ownership info changes behavior quietly and effectively.
- Design for agents, too. Clean APIs and structured catalog metadata make your platform usable by AI coding agents with the same guardrails as humans.
- Steal shamelessly from the CNCF ecosystem. The CNCF Platforms working group publishes maturity models and white papers that save months of design work.
📌 Key Takeaways
- Platform Engineering is DevOps at scale: it keeps the culture but removes the cognitive overload by offering self-service capabilities.
- The Internal Developer Platform is the engine; the Internal Developer Portal is the dashboard. You need both, and the engine matters more.
- Golden paths should be paved, end-to-end, maintained, and faster than the alternative. Voluntary adoption is your north-star metric.
- Zero-trust security belongs inside templates: workload identity, mTLS, signed images, default-deny networking, and policy-as-code.
- Start small with the Thinnest Viable Platform, treat it as a product, and grow it based on real developer pain.
- In 2026, your platform serves both humans and AI agents, which makes clear contracts and guardrails more valuable than ever.
Conclusion
The shift from DevOps to Platform Engineering isn't about throwing away what worked. It's about admitting that asking every developer to master an ever-growing toolchain doesn't scale.
A well-built Internal Developer Portal, backed by thoughtful golden paths and invisible security guardrails, gives developers back their most valuable resource: focused time on the problems that matter to customers. It gives security teams consistency. It gives leadership faster, safer delivery.
If you're starting this journey, don't begin with a tool comparison spreadsheet. Begin by sitting next to a developer and watching them ship something. Note every wait, every copy-paste, every "who owns this?" moment. That list is your platform roadmap.
Then build the smallest thing that removes the biggest pain, and keep going.
References
- Backstage Documentation — Open-source framework for building developer portals
- CNCF Platforms White Paper — Cloud Native Computing Foundation guidance on internal platforms
- CNCF Platform Engineering Maturity Model — Framework for assessing platform maturity
- Team Topologies — Matthew Skelton and Manuel Pais on platform teams and cognitive load
- Crossplane Documentation — Kubernetes-native infrastructure composition
- Argo CD Documentation — Declarative GitOps continuous delivery
- Kyverno Policies — Kubernetes-native policy management
- Sigstore — Keyless signing for the software supply chain
- SLSA Framework — Supply-chain Levels for Software Artifacts
- SPIFFE and SPIRE — Standards for workload identity
- DORA Research — DevOps Research and Assessment metrics and reports
- platformengineering.org — Community resources and talks on platform engineering