Carve a resource out of Terraform
This tutorial carves a single resource out of a Terraform estate into native chant, incrementally and reversibly. You never carve the whole estate — small, cleanly-mappable pieces move; the long tail stays in Terraform.
The whole flow runs offline — no cloud account, no Terraform binary, no
state backend. It works against the bundled estate and its state file. The one
genuinely live part (terraform state rm / apply) is shown but not required
to follow along.
The runnable estate is in
examples/terraform-carve-out.
To watch all four steps at once:
cd examples/terraform-carve-out./demo.shThe rest of this page walks the same steps individually.
Prerequisites
Section titled “Prerequisites”# the chant CLI and the AWS lexicon (the carve emit target)npm install --save-dev @intentius/chant @intentius/chant-lexicon-aws# the HCL parser the carve commands usenpm install --save-dev @cdktf/hcl2jsonRun chant via npx chant (or add node_modules/.bin to your PATH).
1. See what is cheap to carve
Section titled “1. See what is cheap to carve”cd examples/terraform-carve-outchant carve advise --from ./terraformThe estate is ranked into three bands:
CLEAN LEAF — carve now 100 aws_cloudwatch_log_group.api -> AWS::Logs::LogGroup 96 aws_subnet.a -> AWS::EC2::Subnet 88 aws_s3_bucket.assets -> AWS::S3::Bucket 81 aws_lambda_function.api -> AWS::Lambda::FunctionCARVABLE — has boundary work 64 aws_vpc.main -> AWS::EC2::VPCLEAVE IN TERRAFORM 0 random_pet.suffixThe bucket is a clean leaf held back one notch by the one Lambda that reads it.
The VPC is carvable, but three subnets hang off it. random_pet has no native
mapping, so it stays.
2. Bridge the boundary
Section titled “2. Bridge the boundary”Carving the bucket cuts one edge: the Lambda reads it. Generate the edits to the surviving Terraform so its plan stays valid.
chant carve bridge --from ./terraform --select aws_s3_bucket.assets --output ./carveoutThis writes to ./carveout/: a data "aws_s3_bucket" "assets" block, a
rewritten api.tf with the Lambda’s references rewired to data.aws_s3_bucket.assets.*,
and a reversible runbook. Nothing in ./terraform changes. --apply-rewrites
edits the survivor .tf in place instead.
3. Adopt the bucket into chant source (offline, from state)
Section titled “3. Adopt the bucket into chant source (offline, from state)”chant carve emit --from ./terraform --select aws_s3_bucket.assets \ --state ./terraform/terraform.tfstate --output ./carveoutThis writes ./carveout/assets.ts:
// Adopted from Terraform state: aws_s3_bucket.assets -> AWS::S3::Bucketimport { Bucket } from "@intentius/chant-lexicon-aws";
export const assets = new Bucket({ BucketName: "myapp-assets-prod", Tags: [{"Key":"Team","Value":"web"},{"Key":"Env","Value":"prod"}],});A Terraform-managed resource is created through the provider API, not
CloudFormation, so it is not in any CFN stack — its resolved shape lives in the
state file. --state adopts straight from there, no cloud call. (A resource
already in a CloudFormation stack can be adopted live with --env <env>
instead.) The resource now sits at the observe position: emitted, reversible,
nothing applied.
4. Graduate
Section titled “4. Graduate”chant carve apply --from ./terraform --select aws_s3_bucket.assets --env prod --stack assetscarve apply resolves the ownership marker (chant:managed-by/stack/env) and
prints the finalized runbook. It makes no cloud call — the apply is whatever
lifecycle you brought, which stamps the marker the emitted source carries.
The one genuinely live part, when you are ready to hand off for real:
terraform state rm aws_s3_bucket.assets # stop managing it; does NOT destroyterraform plan && terraform apply # apply the bridge patch to survivorsTry it on your own estate
Section titled “Try it on your own estate”Point it at your own Terraform. Two of the four steps work on any tree today; the other two have narrower coverage, so it is worth knowing what to expect before you run them.
-
carve adviseandcarve bridge— any Terraform tree. Both are offline, read-only, and lexicon-agnostic. Run them against your real estate right now:Terminal window chant carve advise --from /path/to/your/terraformchant carve bridge --from /path/to/your/terraform --select <address> --output ./carveout -
carve emitandcarve apply— AWS. Emit produces native chant source for the AWS lexicon across ~50 common carve targets: S3, IAM (role / policy / instance profile / user / group), DynamoDB, SNS, SQS, Lambda, KMS, Secrets Manager, SSM, ECR, CloudWatch (log groups / alarms / event rules), Route 53 (zones / records), EFS, EC2 (instances, VPC, subnet, security group, route table, internet/NAT gateway, EIP, EBS volumes, launch templates), autoscaling groups, ELBv2 (load balancers / target groups / listeners), RDS (instances / subnet groups), ElastiCache, API Gateway (REST / HTTP), Step Functions, ACM certificates, and ECS (clusters / services / task definitions). Advise and emit cover exactly the same AWS types, so anything advise ranks, emit can produce. A type outside that set reports the supported list. Other clouds are not carved yet.
See the carve CLI reference for every flag.