Skip to content

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:

Terminal window
cd examples/terraform-carve-out
./demo.sh

The rest of this page walks the same steps individually.

Terminal window
# 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 use
npm install --save-dev @cdktf/hcl2json

Run chant via npx chant (or add node_modules/.bin to your PATH).

Terminal window
cd examples/terraform-carve-out
chant carve advise --from ./terraform

The 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::Function
CARVABLE — has boundary work
64 aws_vpc.main -> AWS::EC2::VPC
LEAVE IN TERRAFORM
0 random_pet.suffix

The 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.

Carving the bucket cuts one edge: the Lambda reads it. Generate the edits to the surviving Terraform so its plan stays valid.

Terminal window
chant carve bridge --from ./terraform --select aws_s3_bucket.assets --output ./carveout

This 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)”
Terminal window
chant carve emit --from ./terraform --select aws_s3_bucket.assets \
--state ./terraform/terraform.tfstate --output ./carveout

This writes ./carveout/assets.ts:

// Adopted from Terraform state: aws_s3_bucket.assets -> AWS::S3::Bucket
import { 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.

Terminal window
chant carve apply --from ./terraform --select aws_s3_bucket.assets --env prod --stack assets

carve 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:

Terminal window
terraform state rm aws_s3_bucket.assets # stop managing it; does NOT destroy
terraform plan && terraform apply # apply the bridge patch to survivors

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 advise and carve 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/terraform
    chant carve bridge --from /path/to/your/terraform --select <address> --output ./carveout
  • carve emit and carve 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.