The trigger for building a platform is almost always the same story: a handful of teams, each with their own slightly different way of shipping to AWS, each copy-pasting the last team's Terraform and CI config, and a central team drowning in tickets that all boil down to "can you give me a database / a queue / an environment." We hit that wall around fifteen engineers, and the answer wasn't more tickets, it was a platform that let teams serve themselves within guardrails.

An internal developer platform (IDP) is not a product you buy; it's the paved road you build so the easy path is also the compliant one. Here's how I'd structure one on AWS.

What "platform" actually means here

The goal is to raise the level of abstraction developers work at. Instead of a product engineer reasoning about VPCs, IAM policies, and task definitions, they declare "I need a service with a Postgres database and an SQS queue," and the platform translates that into correct, secured, observable AWS resources. The platform team owns the translation; the product team owns the declaration.

The metric that matters is time from "I have an idea" to "it's running in production safely." If your platform doesn't move that number, it's just another layer of indirection.

The layers I'd build

  1. Foundation, multi-account structure via AWS Organizations and Control Tower, with separate accounts per environment and team. SCPs enforce the non-negotiables (no public S3, region restrictions, mandatory encryption).
  2. Infrastructure modules, golden Terraform modules for the common building blocks (service, database, queue, bucket) that bake in tagging, encryption, logging, and least-privilege IAM by default.
  3. Self-service interface, a portal or, more pragmatically, a Git-based workflow where a developer opens a PR with a short manifest and the platform provisions the rest.
  4. Golden paths for delivery, a standard CI/CD pipeline (CodePipeline, GitHub Actions, or Argo on EKS) that any service can adopt without reinventing build, test, scan, and deploy.

Abstraction in practice

The whole pitch lives or dies on the developer-facing interface being genuinely simple. The contract a product team writes should be small:

# service.yaml, the entire interface a product team touches
apiVersion: platform/v1
kind: Service
metadata:
  name: orders-api
  team: commerce
spec:
  runtime: container
  port: 8080
  cpu: 512
  memory: 1024
  resources:
    - type: postgres
      name: orders-db
      size: small
    - type: queue
      name: order-events
  scaling:
    min: 2
    max: 20

Behind that file, a golden Terraform module expands it into an ECS/Fargate service, an RDS instance, an SQS queue, the IAM roles wiring them together, CloudWatch alarms, and the right tags, none of which the product engineer sees. That module is where your standards live:

module "service" {
  source  = "git::https://git.internal/platform/modules//service?ref=v3.2.0"

  name        = var.name
  team        = var.team
  image       = var.image
  port        = var.port

  # platform-enforced defaults
  encryption_at_rest = true
  log_retention_days = 90
  tags = {
    team        = var.team
    managed-by  = "platform"
    cost-center = var.team
  }
}

Build vs. buy the spine

You don't have to build the portal yourself. The realistic options:

ApproachGood fit when…Cost
Backstage (self-hosted)You want a rich service catalog and have platform engineers to run itEngineering time
AWS Service Catalog + ProtonYou want AWS-native, less to operateLower ops, less flexible
Git + Terraform + AtlantisSmall teams, "PR is the interface"Lowest, very pragmatic

I almost always start teams on the Git-based approach. A manifest in a repo, a PR, and an automated apply is 80% of the value at 10% of the operational cost, and it teaches you what abstractions developers actually want before you invest in a heavy portal.

Guardrails, not gates

The difference between a platform people adopt and one they route around is whether your controls block or guide. Prefer guardrails that prevent misconfiguration automatically (SCPs, module defaults, policy-as-code with OPA/Checkov in CI) over manual review gates that just slow people down. If the paved road is faster than going off-road, adoption takes care of itself.

Takeaways

  • The platform's job is to raise the abstraction level so developers declare intent and the platform produces correct AWS resources.
  • Build in layers: multi-account foundation, golden Terraform modules, a self-service interface, and standard delivery pipelines.
  • Start with a Git-and-Terraform "PR is the interface" model before investing in Backstage or Proton, it reveals the abstractions developers actually want.
  • Favor automatic guardrails (SCPs, module defaults, policy-as-code) over manual gates; the paved road must be the fast road or people route around it.