If you've already ruled out AWS Control Tower, the real decision left is OrgFormation vs. CDK landing zone: two genuinely code-driven ways to manage AWS Organizations with no managed console layer in between. Both compile down to the same AWS::Organizations::* API calls and the same CloudFormation stacks. What actually differs is the abstraction level you write in, how safely a change ships before it hits every account in your org, and what's already running the first hour after you start.
If the layer underneath this decision is still fuzzy, how Control Tower relates to Organizations is worth reading first, since both tools here operate directly on Organizations with Control Tower out of the picture.
I build and maintain a production CDK landing zone, and I checked every claim below directly against the OrgFormation GitHub repo. A couple of the things commonly said about it turn out to be wrong, in both directions.
Does CloudFormation Actually Manage AWS Organizations?
Yes. If you found a forum answer from a few years back saying CloudFormation can't touch Organizations at all, that used to be true and no longer is. AWS::Organizations::Account, ::Organization, ::OrganizationalUnit, ::Policy, and ::ResourcePolicy are all native CloudFormation resource types, and CDK exposes them as CfnAccount, CfnOrganization, CfnOrganizationalUnit, CfnPolicy, and CfnResourcePolicy:
import { CfnOrganizationalUnit, CfnAccount } from 'aws-cdk-lib/aws-organizations';
const engineering = new CfnOrganizationalUnit(this, 'EngineeringOu', {
name: 'Engineering',
parentId: rootId,
});
const staging = new CfnAccount(this, 'StagingAccount', {
accountName: 'staging',
email: 'aws-staging@example.com',
parentIds: [engineering.attrId],
});
staging.node.addDependency(engineering);
The honest caveat: these are L1 constructs only. The aws_organizations module's own documentation states plainly that there are "no official hand-written (L2) constructs for this service yet," current as of CDK 2.265.0, and recommends using the L1 properties directly. A second detail worth knowing before you rely on this in production: CfnAccount defaults to DeletionPolicy: Retain, so removing the resource from your stack doesn't close the underlying AWS account. If you need to look up an unfamiliar property on any of these five types while you're writing the stack, the CloudFormation resource properties reference is faster than digging through the CDK API docs mid-edit.
OrgFormation vs CDK Landing Zone: What Actually Differs
Both tools manage the same underlying AWS Organizations API. The difference is what you write and who else has looked at it recently.
OrgFormation is a YAML DSL with its own CLI. An organization.yml file defines your org using OrgFormation's own resource types (OC::ORG::Account, OC::ORG::OrganizationalUnit, OC::ORG::ServiceControlPolicy), wired together with !Ref:
EngineeringOU:
Type: OC::ORG::OrganizationalUnit
Properties:
OrganizationalUnitName: Engineering
Accounts:
- !Ref StagingAccount
StagingAccount:
Type: OC::ORG::Account
Properties:
AccountName: staging
RootEmail: aws-staging@example.com
Reuse across templates comes from !Include (splicing in another YAML file) and Foreach (iterating over a binding). There's no function, class, or loop in the general-purpose sense, because there's no general-purpose language underneath it. A CDK landing zone is TypeScript, so the equivalent OU-and-account definition is ordinary code: a function that takes an OU name and an email and returns both resources, reusable across every account you provision and versionable as an npm package.
Is OrgFormation still maintained? Yes, plainly. The npm package (aws-organization-formation) shipped v1.0.17 on 2026-03-11, the most recent GitHub commit landed 2026-01-19, and the repo carries 1,489 stars, 136 forks, and 41 contributors under an MIT license. One thing worth checking before you build on any niche tool: GitHub's own Releases tab still shows v1.0.14 from April 2024, three versions behind what npm has actually shipped. That gap is what creates a false "abandoned" impression at a glance, not evidence of one. What's genuinely true is a support-model fact, not a knock: AWS's own Prescriptive Guidance for managing Control Tower controls as code names CDK and Terraform as the two supported IaC paths and doesn't reference OrgFormation or any third-party org-as-code tool.
Both tools are also less either/or than the framing suggests. OrgFormation's task runner can invoke CDK and Serverless Framework deployments as steps in the same task file, so some teams run OrgFormation for the org layer and CDK for everything that deploys inside the accounts. Control Tower sits outside this comparison entirely: neither tool needs it, and if you haven't ruled it out yet, the wider five-tool comparison covers where it fits.
What Happens Before a Change Ships
OrgFormation does have a preview step, and the distinction that matters isn't whether one exists but which command you get it from.
OrgFormation splits preview across its two layers. For organization resources, org-formation create-change-set organization.yml generates a named change set you can review before execute-change-set applies it, or print with print-change-set. For the cross-account CloudFormation layer, validate-stacks checks the templates that would be generated per target account without deploying them, and print-stacks prints the generated output. Both are genuine plan-then-apply workflows, comparable to terraform plan.
The gap is perform-tasks, the end-to-end orchestrator that most production automation actually runs. It has no dry-run flag. --perform-cleanup controls whether resources from removed tasks get cleaned up; it isn't a preview mode. So the two primitives underneath have a preview step, but the command that ties them together for day-to-day automation doesn't expose one.
cdk diff is the opposite default: always available, with three modes (auto, change-set, template) trading off speed against accuracy, and it's part of the deploy path rather than a separate opt-in step. A CDK landing zone adds a second, independent layer on top: an offline rule set CDK evaluates against every synthesized template with no AWS credentials needed, plus CloudFormation's six pre-deployment checks run against a real account (three errors: resource property syntax, resource name conflicts, S3 bucket emptiness on delete; three warnings: service quota limits, Config recorder conflicts, ECR repos still holding images). pnpm run validate runs the credential-free check locally or in a pre-commit hook; organization:validate and landingzone:validate add the CloudFormation checks against each target account. Both the deployment workflow and the pull request workflow run this validation before they act, so a broken template fails a GitHub Actions job instead of reaching CloudFormation.
| Step | OrgFormation | CDK landing zone |
|---|---|---|
| Preview org resources | create-change-set (opt-in) | cdk diff (always in the deploy path) |
| Apply | execute-change-set | Merge triggers the pipeline |
| Cross-account CFN preview | validate-stacks / print-stacks | Offline rule set + 6 CloudFormation pre-deployment checks |
| End-to-end automation | perform-tasks, no dry-run flag | pnpm run validate + CI assertions gate both workflows |
The OrgFormation CLI reference documents all of these commands directly if you want to verify the exact flags yourself.
What You Get on Day One
Point both tools at a fresh AWS Organization and ask what's actually running an hour later, and the answer diverges more than the change-safety story does.
OrgFormation is a deployment engine, not a pre-built landing zone, and it doesn't pretend otherwise. org-formation init scaffolds a starter organization.yml by reverse-engineering your existing accounts and OUs, and init-pipeline adds CodeCommit, CodeBuild, and CodePipeline scaffolding around it. What it doesn't ship is any SCP content, any security-service baseline, or IAM Identity Center configuration. That's a deliberate design choice, not an oversight: OrgFormation's own README frames the tool's value as ongoing maintenance of org resources you define yourself, in contrast to an account-vending-machine model. Whatever runs in your accounts, you wrote it.
A CDK landing zone ships nine named CloudFormation StackSets that fan out automatically the moment an account joins a targeted OU, no enrollment step required:
| StackSet | What it deploys | Target |
|---|---|---|
| LogArchiveStackSet | Centralized CloudTrail storage buckets | Log archive account |
| CentralAlertsStackSet | Encrypted SNS topic for CloudTrail notifications | Security account |
| ProvisionManagementStackSet | Secure defaults + optional account-quota request | Management account |
| AccountSecurityStackSet | Default VPC removal, EBS encryption, S3 Block Public Access, password policy | Every member account |
| OrganizationSecurityStackSet | Org-wide CloudTrail, centralized root access, IAM Access Analyzer | Security account |
| CostControlStackSet | AWS Budgets + Cost Anomaly Detection | Every member account |
| CdkBootstrapStackSet | CDK bootstrap roles, asset bucket, ECR repo | Dev + Production OUs |
| ServiceQuotasStackSet | Service quota increase requests | Dev, Production, Security OUs |
| SecurityHubV2StackSet | Security Hub CSPM, GuardDuty, Inspector, Macie | Security account |
Four of these run under CloudFormation's service-managed permission model, which is what makes the automatic OU targeting work: CloudFormation creates the IAM roles itself and triggers stack-instance creation the moment an account joins a targeted OU, no manual enrollment step. The remaining five (log archive, central alerts, the management account, organization security, and Security Hub V2) run self-managed, because each targets one specific account directly rather than an OU. Self-managed is also the only model of the two that can reach the management account at all.
If an auditor is asking about how quickly a new account reaches a compliant baseline, timing matters more than most teams expect for how that evidence gets produced.
Where Each Tool Hits a Ceiling
Three numbers are worth knowing before you commit to either approach at scale, and one of them changed recently enough that it's worth checking the date on whatever you read next.
SCP quota. AWS raised the service control policy quota from 5 to 10 per root, OU, or account, and the maximum SCP size from 5,120 to 10,240 characters, in a What's New announcement dated May 2026. If a source you're reading cites "5 SCPs," it predates that change. Neither tool changes this quota; it's an AWS Organizations limit both operate under identically. For the mechanics of how SCPs actually evaluate against each other once you're past the quota question, how SCPs actually work covers the evaluation logic.
Template size. CloudFormation caps inline templates at 51,200 bytes. That's a real constraint for OrgFormation's YAML-based org definitions once an organization grows large: a flat organization.yml describing dozens of accounts, OUs, and policies can approach it. CDK sidesteps the ceiling by construction, since a TypeScript loop generating the same structure never writes out the intermediate YAML by hand.
State recovery. OrgFormation stores all of its org-resource state in a single, self-managed S3 object, by default organization-formation-${AWS::AccountId}/state.json. The documented recovery path for corruption is blunt: delete the state bucket and start over with init. There's no partial-recovery or state-import tooling beyond that. Back this bucket up, or at least understand the recovery path, before you rely on it in production. CloudFormation keeps stack state inside the service itself, with native drift detection and change sets, so there's no equivalent user-managed file to lose, though OrgFormation's own "annotated CloudFormation" layer, the per-account stacks it generates, does inherit that native state model at the individual-stack level.
OrgFormation vs CDK Landing Zone: Side by Side
| Criterion | OrgFormation | CDK landing zone |
|---|---|---|
| Abstraction | YAML DSL + custom CLI | General-purpose TypeScript |
| Preview before apply | Opt-in two-step change set; perform-tasks has no dry run | Always-on cdk diff + offline validation + CI assertions |
| Day-one output | Engine only, you write the baseline | 9 StackSets fan out automatically to targeted OUs |
| State / drift model | Self-managed S3 state.json; manual reinit on corruption | CloudFormation-native state + drift detection |
| Scale ceiling | 51,200-byte inline template limit | Programmatic generation, no template-size ceiling |
| Maintenance status | Community, active (npm v1.0.17, March 2026) | AWS maintains CDK itself; the landing zone packages are versioned and maintained by us |
| AWS bill impact | None, same underlying services either way | None, same underlying services either way |
That last row is worth stating directly: AWS Organizations, CloudFormation, and StackSets are free either way, and the paid line items in a landing-zone baseline (Config, CloudTrail, GuardDuty, Security Hub, Inspector, Macie) get billed identically regardless of which tool provisioned them. Choosing between these two tools doesn't change your AWS bill; it changes your engineering time.
How to Decide
A few criteria that actually move the decision, rather than a generic maturity model:
- Already CloudFormation-native, with infrequent org changes? OrgFormation is a defensible, free, actively maintained choice. The missing
perform-tasksdry run is a manageable risk if you're not shipping SCP or OU changes weekly. - Already writing CDK for applications? The runway is short: same language, same diff-and-assert workflow, now applied to the organization itself instead of just your workloads.
- Need unit-testable, offline-checkable templates before anything touches production? CDK's assertions library and the CDK landing zone's pre-deployment checks are a real capability gap OrgFormation's YAML templates don't close.
- Expecting fast account growth or a multi-region rollout? StackSets' automatic OU-based fan-out matters more the faster your account count grows.
One fit-caveat worth stating plainly: a CDK landing zone assumes CDK and TypeScript familiarity your team either already has or wants to build. If nobody on the team has written CDK before, that's a real ramp, not a weekend detour.
Frequently Asked Questions
Is a CDK landing zone worth it if my team already uses OrgFormation?
Do I need AWS Control Tower to use either OrgFormation or a CDK landing zone?
What does moving from OrgFormation to a CDK landing zone involve?
Does switching from OrgFormation to a CDK landing zone change my AWS bill?
Am I locked in if I build on OrgFormation or a CDK landing zone?
Should I run OrgFormation for the org layer and CDK for everything else?
Next step
See the CDK Landing Zone That Ships the Baseline OrgFormation Leaves to You
The nine StackSets, offline validation, and always-on cdk diff described above are running in production landing zones we deploy and keep evolving. Explore what your organization would run on day one instead of writing it yourself.
Key Takeaways
Both tools are genuinely Control-Tower-independent and code-driven; the decision between them isn't about escaping a managed console, it's about abstraction level, change-safety, and what's running on day one. OrgFormation is actively maintained and does have a real preview workflow, just not on perform-tasks, the command most production automation runs through. A CDK landing zone's advantage isn't a longer feature list, it's that cdk diff, offline validation, and CI assertions sit in the deploy path by default rather than as an opt-in step. The SCP quota doubled in May 2026, so verify any older source you're reading against that date before trusting its numbers.
If you want a concrete next step rather than a verdict, open your current org definition and count two things: how many SCPs sit on your busiest OU, and how many people could describe what a change to it would touch before it deployed. Those two numbers decide this more reliably than any feature table, including the one above.
If Control Tower itself is still on the table for you, AWS Control Tower vs CDK landing zone covers that decision next.