The goal of this project is to implement a reference architecture for an internal developer platform (IDP) based on the general architecture provided by the platformengineering.org community.
Other resources that influenced this project:
- Platform Engineering for Architects: Crafting Modern Platforms as a Product by Max Körbächer, Andreas Grabner, and Hilliary Lipsig
- Team Topologies, 2nd Edition: Organizing Business and Technology for Fast Flow of Value by Matthew Skelton and Manuel Pais
- The DevOps Handbook, 2nd Edition: How to Create World-Class Agility, Reliability, & Security in Technology Organizations by Gene Kim, Jez Humble, et al.
- Several talks from the @PlatformEngineering YouTube channel
Traditionally, development and operations of software lived in separate worlds. Developers wrote code and threw it "over the wall" to IT operations teams, who were responsible for provisioning infrastructure, deploying applications, and keeping everything running in production. The two groups had fundamentally different incentives. Developers optimized for shipping features while ops teams optimized for stability. This caused a lot of friction and inefficiencies between the teams. Deployments were infrequent, risky, and heavily coordinated affairs. When something broke in production, blame was shifted between the teams. The industry recognized this dysfunction and responded with DevOps: a cultural and organizational philosophy that collapsed the wall between dev and ops under the motto of "you build it, you run it". Teams became cross-functional, deployment pipelines got automated, and for some time, things worked.
As organizations scaled and the cloud-native ecosystem exploded, "you build it, you run it" quietly mutated into something far more demanding: you build it, you run it, you provision it, you secure it, you monitor it, and you debug it at 3am. Developers who signed up to write product code found themselves drowning in infrastructure configurations, security requirements, and setting up observability and alerting. Teams chose their favorite tooling and reimplemented the same things over and over again, which made it nearly impossible to enforce organization-wide standards and compliance requirements. Organizations that tried to avoid this by keeping centralized ops teams instead just recreated the original bottleneck. A term was coined for this: TicketOps. Application teams submit their requests to the central Cloud Engineering team, that handles most or all infrastructure related changes.
Platform engineering is the industry's current answer to this second failure. Rather than forcing developers to become infrastructure experts or blocking them behind centralized gatekeepers, it treats the internal infrastructure layer as a product. This is built by a dedicated platform team, designed around the needs of developer users, and delivered through self-service golden paths, templates, and portals. Developers get autonomy and speed; the organization gets consistency, governance, and the ability to enforce security and cost controls centrally. Spotify's experience is illustrative: after building Backstage, their internal developer platform, they measured a 55% reduction in "time to 10th commit" for new engineers. Platform engineering is ultimately the recognition that DevOps as a philosophy always needed a concrete implementation layer, and that layer must be treated with the same product discipline as the customer-facing software it exists to support.
The code for my IDP is split into several repositories.
All repositories on GitHub are only a mirror. The main work is done on my self-hosted GitLab instance, which has two self-hosted GitLab runners attached.
- idp-argocd-platform-apps: This repository contains all core platform applications and follows the Argo CD app-of-apps pattern.
- idp-crossplane-compositions: Crossplane compositions for custom resource definitions (XRDs).
- idp-portal: Frontend and backend code for the Backstage application.
- idp-portal-deployment: GitOps repo for the Backstage deployment.
- idp-catalog: Collection of backstage entities that are not synced from other sources.
- idp-argocd-user-apps: Holds references to all applications created by developers via the self-service capabilities of Backstage.
- idp-template-backstage-system: Template to create a new System entity in Backstage.
- idp-template-python-fastapi: Template to create a new API based on Python and FastAPI.
While I mainly develop the IDP in my homelab, I also wanted to deepen my knowledge of AWS. Thus, I have set up a cloud version of my homelab, supporting two environments (dev and prod), with the main focus on AWS EKS. Configuration is split into the following repositories:
- idp-terraform-aws-bootstrap: AWS landing zone for my IDP reference implementation. The landing zone is designed to be long-lived while workloads are ephemeral.
- idp-terraform-aws-infra: AWS infrastructure for the IDP. This deploys the VPC, HashiCorp Vault (to match my homelab), EKS, and bootstraps the EKS cluster with Karpenter, Envoy Gateway and ArgoCD configured. Common applications between the cloud and homelab implementation are handled in idp-argocd-platform-apps. The repository is built in such a way that I can automatically deploy everything from scratch without any intervention and destroy everything again after I'm done working on it. This way, I fully utilize the cloud by only using the resources when I'm working on implementing new features.
This is an overview of the current self-service capabilities of my IDP reference architecture.
If you are interested in a more technical overview, you can read the architecture description.
Creating a new application in a self-service fashion works like this:
- For each application type, there is a dedicate template repository that contains all the application and deployment code.
- When creating a new application, the following steps are performed by Backstage:
- Create the application repository (i.e., where the application code lives) from the template. This should contain a starting point for the team with tooling, CI/CD pipeline configuration, and observability already included.
- Create the deployment repository, which is used to deploy the application via GitOps.
- Create a new application environment (using the
ApplicationEnvironmentXRD from idp-crossplane-compositions), which sets up a namespace, the ArgoCD application, and security guardrails (not yet implemented). - Register the new application in Backstage
- When the application repository is created, the first pipeline run kicks in. The pipeline runs linting and testing steps, builds the Docker image, pushes it to the GitLab container registry, and updates the image tag in the deployment repository.
The whole process (filling out the form, creating the templates, first build and deployment) takes less than 5 minutes for the application to be up and running.
Below, you find a collection of screenshots how this looks like when creating a new API based on Python and FastAPI:
Creating an application requires the following information
- Human readable name of the application
- System to which the application belongs to
- Description of the application
- Hostname where the application should be available
- Team that owns the application
- Visibility of the repositories that will be created
Confirmation screen after the application has been created. Links are provided to the application repository, deployment repository, and the link to the catalog entry in Backstage.
Backstage catalog entry:
ArgoCD view of the application:
Confirmation that the DNS entry is registered and the application is available over HTTPS:
With this, developers can register a new system (entity type in Backstage's system model).
Creating a new backstage system requires the following information:
- Human readable name of the system
- Description of the system
- Team that owns the system
Confirmation screen after the system has been created:
New system in Backstage:








