awsguides

Why dev and prod should never share an AWS account

Separate dev and prod environments by AWS account, not by naming convention. What goes wrong when they share, and when to add the second account.

By Pierre Sauvignon · · 7 min read

The TigerSoup tiger standing between two fenced gardens, a sandbox on one side and a tidy blooming garden with a closed gate on the other

Separate dev and prod environments should mean separate AWS accounts, not a naming convention. If a mistake in dev can physically reach prod, they are not separate, however carefully the resources are tagged. The boundary that works is the account boundary, because it is enforced by AWS rather than by everyone remembering to be careful.

This post covers what “separate” should actually mean, three concrete ways shared environments go wrong, how deploys to each should differ, when to add the second account, and what it costs. The short version of the last one is: nothing.

What “separate” should mean

Separate means a different AWS account, with its own credentials, its own IAM, its own bill, and its own service quotas. Anything less is a label.

There are three common ways people try to separate environments:

ApproachWhat separates themWhat can cross the line
Naming and tags (myapp-dev-db, env=prod)A stringEverything. Any role with access to the account can touch both.
Separate VPCs or regions in one accountNetwork placementIAM, billing, quotas, and any CLI call with the wrong flag.
Separate AWS accountsThe account itselfOnly what you deliberately allow across accounts, which by default is nothing.

The first two are better than nothing, but they share a weakness: the thing keeping dev out of prod is a person or a policy getting it right every time. The account boundary does not need anyone to get anything right. A credential for the dev account cannot act in the prod account because, as far as AWS is concerned, it does not exist there.

This is the same logic as giving each project its own account, applied one level down. If you have read why every project should have its own AWS account, the argument will feel familiar: isolation that is structural beats isolation that is procedural.

What goes wrong when they share

When dev and prod share an account, three things eventually happen: a dev operation hits a prod resource, a permission change meant for dev applies to prod, or a dev experiment runs up a bill that lands next to prod’s. Here is each one in enough detail to recognise.

The wrong table

Someone runs a cleanup script against dev. It lists DynamoDB tables with a prefix, finds myapp-users instead of myapp-dev-users because the prefix was wider than intended, and deletes it. The script worked exactly as written. The table it deleted was simply reachable.

In a separate account, the script lists tables in the dev account and the prod table is not in the list. There is nothing to get wrong.

The permission that applied everywhere

A developer needs broader access to debug something in dev, so an IAM policy gets widened. The policy is attached to a role that, because there is one account, also has access to prod resources. Weeks later, an AI coding agent or a tired human uses that role for something routine and the broad permission is what makes the mistake possible.

In a separate account, widening dev access widens dev access. Prod IAM is untouched because it is a different IAM.

The experiment on the same invoice

A load test, a forgotten EC2 instance, a Lambda in a retry loop. The bill arrives, and it is one bill, so there is no quick way to tell whether the number is prod traffic or a dev mistake. Working it out means tags, Cost Explorer filters, and an afternoon.

In a separate account, the dev bill is the dev bill. If it is wrong, you know which environment to look at, and a budget alert on the dev account fires without any filtering. There is more on that in how to avoid a surprise AWS bill.

None of these are rare, and none of them are caused by carelessness in the usual sense. They are caused by two things being reachable from the same place. The fix is to make them not reachable from the same place.

How deploys should differ

Dev should deploy from any branch, automatically, with no approval. Prod should deploy from main, or from a gated environment, with a different role in a different account. The two paths should not share credentials.

In practice that looks like:

The roles are the enforcement. A dev workflow cannot deploy to prod, not because of a rule in a README, but because the prod account’s trust policy does not recognise it. The mechanics of those trust policies, and why they should use short-lived credentials rather than stored keys, are in keyless deploys with GitHub Actions and OIDC.

This split also matters for AI coding agents. An agent should be free to push to a branch and see its work on a dev URL, and it should hit the same gate a person would before anything reaches prod. Keeping prod behind an account boundary is what makes that gate real rather than advisory.

When to add the second account

Start with one isolated account per project. Add a prod account when there is something to protect: real users, real data, or a URL you have told people about. Before that point, the project account is dev, and there is nothing for it to be separate from.

The reason to delay is not cost, since the account is free. It is that early on, the only user is you, the data is test data, and a broken deploy is a broken deploy of nothing. A second account at that stage adds a step without removing a risk.

The reason to not delay too long is that the first real user tends to arrive quietly, and the moment you notice you have one is usually the moment after a dev mistake affected them.

The trick is to have the structure ready so that adding the account is a toggle, not a rebuild:

If the project was set up this way from day one, “add prod” is an afternoon. If it was set up in one shared account with keys in secrets and resources created by hand, “add prod” is a migration. TigerSoup sets projects up the first way: each project gets its own account under an Organization, and adding separate dev and prod is one toggle later.

What it costs

A second AWS account costs nothing on its own, and the setup time is small if the first account was done properly.

Compare that to the cost of the three failure modes above. One deleted prod table pays for a lot of empty accounts.

Closing

Separate dev and prod environments by account, because the account boundary is the only one that does not depend on everyone being careful every time. Dev deploys from branches without ceremony, prod deploys from main through its own role in its own account, and a mistake in one cannot reach the other. Add the prod account when there is something to protect, and set things up so that adding it is a toggle.

TigerSoup does that setup for free on Mac: a project gets its own AWS account under an Organization, a private GitHub repository, and keyless deploys with production gated from the start. Adding separate dev and prod later is one toggle, and nothing it creates costs anything until you run something.

Frequently asked questions

Is a separate AWS account for prod overkill for a small project?

No. AWS accounts have no monthly fee, and the boundary costs nothing until something runs. The overkill is a prod outage caused by a dev script.

Can I separate dev and prod with tags and naming instead?

You can label them that way, but a tag is not a boundary. An IAM policy, a CLI command with the wrong profile, or a budget overrun can still cross from one to the other.

When should I add the prod account?

When there is something to protect: real users, real data, or a URL you have told people about. Until then, one isolated project account is enough.