AWS ended support for the Copilot CLI on June 12, 2026 and archived the repository ten days later. If you deployed ECS services with Copilot, they keep running: Copilot was only ever a generator of CloudFormation stacks.
The trouble starts when you try to leave. Most teams want those services in Terraform, and the obvious plan is "recreate it in Terraform, then delete the Copilot stacks." Done naively, that plan deletes production.
The four traps
I read through Copilot's source to map exactly what happens when its stacks are deleted. Four things stand out.
1. Custom-resource Delete handlers. Copilot ships 13 Lambda-backed custom resources, and 9 of them do something destructive on Delete. When the environment stack goes, they:
- delete the ACM certificate and its DNS validation records,
- delete every Route 53 alias record for your custom domains,
- delete the NS delegation record in the app's hosted zone,
- empty the ELB access-logs bucket, every object version included.
Importing those resources into Terraform first doesn't save you: the Lambda doesn't care who manages the certificate now.
2. The env-controller. Each service stack carries an EnvControllerAction custom resource. When the last service that needs a shared ALB, NAT gateways or EFS is deleted, the env-controller updates the environment stack and removes them. Delete your last service stack and your load balancer and file system go with it.
3. Unprotected addons. Aurora, DynamoDB and S3 addons live in a nested stack with no DeletionPolicy. Delete the parent and CloudFormation deletes your database.
4. --retain-resources doesn't help. The flag everyone reaches for only works on stacks already in DELETE_FAILED.
Adopt in place instead of rebuilding
The safe sequence is:
- Put
DeletionPolicy: RetainandUpdateReplacePolicy: Retainon every resource in every stack, nested stacks and the StackSet included. Retain on aCustom::*resource also stops CloudFormation from invoking its Delete handler. - Import every resource into Terraform with the exact values it runs with today, so the first plan is import-only.
- Delete the Copilot stacks. CloudFormation forgets the resources; nothing is deleted.
Doing that by hand across dozens of resources is error-prone, so I built a tool for it.
ecsodus
ecsodus is an open-source CLI (Apache-2.0) that does exactly that sequence and nothing else:
uvx ecsodus inventory --app myapp -o inventory.json # read-only discovery
uvx ecsodus report inventory.json # REPORT.md: what's safe, what's blocked, why
uvx ecsodus generate inventory.json --out infra/ # Terraform + retain patches + RUNBOOK.md
The design choices that matter for a tool like this:
-
Read-only by construction. Every AWS client is wrapped in a guard that refuses anything but
Describe,List,GetandLookup. ecsodus never applies Terraform, deletes anything or moves traffic. You run the runbook. -
Exact imports. Each resource becomes a flat
aws_*block built from literal deployed values, andecsodus check --phase importrejects any plan with an update, create, delete or replacement. -
Policy-only change sets. The retain patch edits the deployed template line by line, and
check --changesetaccepts a change set only if it changes deletion policies and nothing else. - Never split a stack. If anything in a stack is unsupported, the whole stack (and everything that depends on it) stays on Copilot, and the report says why.
- An honest baseline. Every report starts with the zero-risk option: keep the CloudFormation.
Does it work?
On September 30 I ran it end to end against a real Copilot v1.34.1 app (an environment, a Load Balanced Web Service, DynamoDB and S3 addons; 5 stacks, 49 resources) in a sandbox account:
- 44 of 44 resources imported, 0 changed, 0 destroyed.
- Every Copilot stack and the StackSet deleted.
- The service kept returning HTTP 200, and the sentinel data in DynamoDB and S3 survived.
- The env-controller and rule-priority Lambdas were never invoked on teardown.
The full report is in the repo: docs/e2e/2026-09-30-aws-e2e.md.
What it doesn't do yet
It's alpha. v0.1 supports Load Balanced Web Services and Backend Services, their environment, and Aurora/RDS, DynamoDB and S3 addons. Worker Services, Scheduled Jobs, Request-Driven Web Services, Static Sites, NLB, CloudFront, sidecars and pipelines are detected and reported as blocked. App Runner is next.
If you're still running something on Copilot, I'd like to hear what it is. Run ecsodus inventory and ecsodus report (both read-only) and open an issue with what's blocked: that's how the roadmap gets set. And if the tool saves you a bad afternoon, a star on GitHub helps other Copilot users find it.

Top comments (0)