walter.bio

Decoupling customer features lifecycle from platform features lifecycle.

Why AWS account separation is not lifecycle separation, and what leaders must do instead

8 November 2026 · 11 min read · platform-engineering, architecture, opinion

Last week, during an incident, I ask my peers: "if our platform lifecycle were not coupled with the feature teams lifecycle, would this incident happen?"

Plaform Engineer
What you mean?
Me
What environment do we use to develop and test our platform services?
Platform Engineer
In dev
Me
Whose dev?
Platform Engineer
¯\_(ツ)_/¯
Me
platform-prod serves customers. platform-dev and platform-staging serve nobody but you and your team.

In many companies, the answer is: the same Dev that the stream-aligned I use stream-aligned teams to refer to feature teams or product teams or those teams that build the products that bring money to the company. teams e to do their daily work. The platform team builds secrets, service discovery, data catalogs, and storage. stream-aligned teams depend on those services from the first commit. When the platform team tries a new version of a service "in Dev", they try it on the environment where other people work.

From the point of view of the platform team, customer Dev is a production environment.I use "customer" for the internal stream-aligned teams that consume platform products. The platform team is the provider. The feature teams are the customers. It has a lower service level than Live. It is not a sandbox. If a platform engineer must treat every experiment as a customer-impacting change, then the platform team has no Dev environment at all. Leadership must prioritize one.

How we got here (as Industry)

The story is common, so I will tell it in general terms.

At the start, infrastructure provisioning ran from CI jobs. The job connected to a host inside the target cloud account, and ran Terraform there. Everything lived in the same account.

Then many organizations introduced a control plane architecture pattern. A dedicated AWS account with environments for the systems and components that managed and provision all the other AWS accounts. Account vending followed. Each biz unit received a Dev, a Staging, and a Live account, a repository, and a central governed baseline. The same model was applied to other platform products due security or workload characterization requirements.

Platform (dev, staging, prod) accounts were also provided for platform teams to collaborate and deploy their own backend services, frontend, schedule jobs, implementing solution space for each of the problem domains they own.

At this point, everyone believed that the problem was solved. The platform had its own accounts. The accounts were isolated. What was missing?

The missing piece was this: Direction. We didn't make it clear that the platform dev and pre-prod accounts should not be expose to customer dev, pre-prod environments. In other words, customer dev environment is provisioned and receive value from systems running on the platform-prod. When platform-dev serves customer-dev. Platform Live serves customer Live. The accounts are separate, but the lifecycles are coupled. When the platform team changes Platform Dev, the change is visible to every feature team that works in customer Dev, at the same moment, with no gate between them.

This is what I meant by "Account separation is-not life-cycle separation."

Two meanings of "Platform Dev"

The phrase "Platform Dev" hides two different things.

The first meaning is the place where the platform team experiments. A new version of the secrets service. A migration of the data catalog. A breaking change to a service discovery name. This is development work. It fails often, and it must be allowed to fail.

The second meaning is the deployed platform service that feature teams use while they work in Dev. This is a running service with users. When it breaks, people stop working.

In most companies, both meanings point to the same environment. The same cluster, the same catalog, the same bucket, the same account. That is the architectural problem. It is not a question of where the resources are hosted. It is a question of whose release lifecycle controls them.

A provider and a consumer must have independent lifecycles. The provider needs a place to be wrong. The consumer needs a service that is right.

The cost leaders pay

When the two meanings collide, the cost does not show up as an incident. It shows up as friction, and friction is hard to see from the top.

  • Coordination overhead. Low-risk platform work needs announcements, approvals, and change windows, because any change can affect someone. Engineers learn to ask permission for experimentation.
  • Slow feedback loops. A platform engineer cannot deploy a half-built version and see what happens. They must get it right before the first deploy. That is the slowest way to learn.
  • Unmeasured blast radius. The platform and the feature teams share catalog namespaces, buckets, and discovery paths. Nobody knows what an experiment can touch, so everybody assumes the worst.
  • Unclear ownership. "Who promoted this version to Dev?" has no clear answer when Dev is both the test target and the serving environment.

I do not give numbers here, because the numbers belong to your company. But I ask you to measure them. Count the approvals that a platform change needs before it reaches customer Dev. Measure the time from a code change to a usable test environment. Ask your platform engineers how many ideas they did not try.Meta's production engineering team gave a talk on this topic, "Architecting a Production Development Environment for Reliability". The title says it: their development environment is production, and they treat it that way.

"But Dev is Dev"

The common objection is this: "Dev is a development environment. Feature teams must accept some breakage there. That is what Dev is for."

I disagree, and the disagreement is about whose work happens there.

Customer Dev is where feature teams do their work. It is their workbench. When a platform change breaks the secrets service in Dev, a feature team cannot deploy, cannot test, and cannot ship. For them, it is a production incident against their velocity.

But its not just velocity, under a regulated environment, you can't ship a fix to production without passing through dev first, its called Environment Promotion. Environment promotion moves a single built artifact through a chain of runtime environments - typically dev, staging and production - running the same tests and health checks at each stop. Source: https://glossary.deployment.to/environment-promotion/

A lower service level is correct. Customer Dev does not need the same availability as Live. But a lower service level is not a zero service level. The platform team must know what level it offers, and it must have a place to break things that is not someone else's workbench.

The honest version of "Dev is Dev" is this: "We did not fund a development environment for the platform team, so we use yours."

What to fund

The fix is not a new account layout. It is vocabulary. Today most companies have one axis, Dev, Staging, Live, and the platform services sit on it next to the feature teams. I propose three axes, each with its own noun and its own owner.

  • Stage answers: how much do we trust this build? The values are platform-dev, platform-staging, platform-prod. A build moves through them in order. The platform team owns this axis.
  • Maturity answers: how much do we promise about this contract? The values are internal, beta, and stable. A stable version gets a number: v1, then v2, v3, and so on. Each new number starts again at internal and moves up.This is the Kubernetes model: v2alpha1, v2beta1, v2. The Kubernetes API deprecation policy states what each level promises. Alpha can be dropped at any time. A deprecated beta version must stay served for nine months or three releases. A stable version is never removed within the same major release of the product. Copy this policy instead of writing your own. All levels ship in the same build. A gate decides who can call each one. internal is open to platform-owned tenants only. beta is open to early adopters who opt in. A stable version is open to everyone. The platform team owns this axis too.
  • Environment answers: where does the consumer work? The values are Dev, Staging, Live. The stream-aligned teams own this axis. For the platform, these are deployment targets, not pipeline stages.
flowchart TB
    subgraph stage["Stage"]
        PD["platform-dev"] --> PS["platform-staging"] --> PP["platform-prod"]
    end
    subgraph maturity["Maturity"]
        I["internal"]
        B["beta"]
        V["stable: v1, v2, ..."]
    end
    subgraph env["Environment"]
        PT["platform-owned tenants"]
        CD["customer Dev"]
        CS["customer Staging"]
        CL["customer Live"]
    end
    PP --> I
    PP --> B
    PP --> V
    I --> PT
    B -. opt in .-> CD
    V --> CD
    V --> CS
    V --> CL

Read the diagram from left to right. Only platform-prod touches the environment axis. platform-dev and platform-staging serve nobody but the platform team, so the team can be wrong there. One released instance serves customer Dev, Staging, and Live alike, and it is held to the Live standard. The three contract versions ship in that one instance. Promotion of a contract is a change of exposure, not a change of place.

Three sentences hold the model. A build moves through stages. A contract moves through maturity levels. A consumer picks an environment. The platform team owns the first two and promises the third nothing it has not written down.

Customer Dev becomes a deployment target for the platform, not a synonym for Platform Dev.Whether the provider axis needs separate accounts or only separate clusters and namespaces is a per-component decision. Security and blast radius decide it. The lifecycle split comes first.

This costs money. The platform team needs environments that it can create and destroy, test data that it can use without permission from a data owner, and a promotion pipeline. It also costs some duplication. That is the price of a provider that can be wrong in private.

Here is the test I ask you to apply. Pick the most dangerous change on your platform roadmap. A catalog migration, a new identity provider, a breaking change to a shared storage layout. Ask the team: "Can you run this end to end, today, without a change to anything that a feature team uses?"

If the answer is no, your platform team has no Dev environment. They have been borrowing yours. Give them one.

My recommendations

These are the conclusions I give to my own teams. They follow from the two axes above, and from the cases where the two axes were not enough.

Recommendation In practice Why
Map platform-prod to customer Dev, Staging, and Live One released instance serves all three customer environments. platform-dev and platform-staging serve nobody but the platform team. The names become honest. "Dev" stops meaning two things.
Hold platform-prod to the Live service level On-call, alerting, and change control match the strictest consumer, even when the caller is a Dev stack. A platform-prod incident is a Live incident.
Make platform-staging the gate Keep copies of real consumer stacks there, with synthetic or masked data. If staging is thin, the first real test of a release happens in platform-prod.
Use three words and never mix them Stage is how much we trust a build. Maturity is how much we promise about a contract. Environment is where the consumer works. A reader can hold three axes when each has its own noun.
Never say "Live" on the platform axis or "prod" on the customer axis platform-prod serves customer Live. platform-dev can never be confused with customer Dev. One word per axis removes the ambiguity that caused the problem.
Promote the binding, not the backend Register the new contract version in customer Dev first, then Staging, then Live. The backend serves both versions during the window. All customer environments call one backend, so rollout must happen at the contract.
Expand and contract, always Add first. Remove later. Never break a registered version. Dev on v1.2 and Live on v1.1 must both work against the same platform-prod.
Canary inside platform-prod A new build takes a slice of traffic before it takes all of it. "Try it in dev first" no longer exists, because dev has no customers.
Share the control plane, split the data plane One platform-prod instance manages per-customer-environment buckets, catalogs, and tables. Customer Live data must not sit where customer Dev can read it.
Maturity is exposure, not location internal, beta, and stable (v1, v2, …) ship in the same build. A gate decides who can call each. internal is open to platform-owned tenants only. Mapping internal to platform-dev puts the maturity axis on top of the stage axis and you are back to one axis.
Name the interaction mode per maturity level internal: platform team alone. beta: time-boxed collaboration with named early adopters. stable: X-as-a-Service. Publish it in the Team API. Permanent collaboration with consumers is a sign that the platform is not a product yet.
Treat internal_v1 in a shared service as a workaround Feature gate off by default. Additive changes only on shared storage. Metrics split by version. A written end date. Interface isolation gives freedom on the contract, none on the runtime. Every change is still a production deploy.
Measure the friction Count approvals per platform change. Measure lead time to a usable test environment. Ask engineers how many ideas they did not try. The cost of coupling shows up as friction, not as incidents, and friction is invisible from the top.