# flow-as-code > Open-source tooling that moves an Amazon Connect flow between accounts, regions and instances without a per-environment ARN mapping table: references are held as `${cdref:type:name}` tokens and resolved by AWS CDK or Terraform/OpenTofu at deploy. Typed authoring in TypeScript, a visual editor, lint, simulate-based testing and export from a live instance all round-trip through one interchange format called FlowDoc. The problem it solves: an Amazon Connect flow is a JSON document full of literal ARNs, and the ARNs differ per account, per region, per instance. Promoting one flow from dev to prod therefore means maintaining a mapping from "the queue I mean" to "the ARN it has in this environment", and something has to rewrite the document before each deployment. flow-as-code makes the flow a typed TypeScript file and a JSON document that hold references as `${cdref:type:name}` tokens instead of ARNs; the deploy path (CDK tokens, or Terraform resource references) resolves them per environment. A literal ARN in authored content fails a hard lint rule. Codegen writes the same document back as TypeScript byte-identically on every run (`packages/core/src/roundtrip.test.ts`), so a change to a flow is a diff a reviewer can read rather than a re-exported JSON blob. Where that claim is held to what the tools do: `examples/promote-across-environments/` (published below) is one FlowDoc reaching a dev and a prod environment on both deploy paths, and `tests/promoteAcrossEnvironments.test.ts` asserts that the two emitted Terraform trees differ in exactly one file, `flow_refs.tf`, and that the CDK path takes no map at all. The Terraform path does take an `--address-map`, which is a different object from the ARN table above: its values are Terraform addresses of resources the reader's own configuration manages, and the emitter refuses any value matching `arn:aws` outright. Status: the repository is public and Apache-2.0. The five packages are published to npm under the @flow-as-code scope, versioned together and released as a set, so install them at matching versions. The studio demo below is live and runs entirely in the browser, with no install and no account. ## Start here - [Landing page](https://flow-as-code.dev/): the ARN table the tooling exists to delete, the token that replaces it, and the packages. - [Studio demo](https://flow-as-code.dev/studio/): the visual editor running read-only in the browser on a demo flow, no account, no network calls. - [Promote one flow across two environments](https://flow-as-code.dev/docs/promote-across-environments/): the runnable version of the thesis, and what it does not claim. - [Documentation index](https://flow-as-code.dev/docs/): every document listed below, with a one-line summary each. - [Source on GitHub](https://github.com/flow-as-code/flow-as-code): the monorepo, issues, and the license. ## Packages Five packages, versioned together and released as a set. - @flow-as-code/core: typed builder, synth, codegen, lint engine, FlowDoc interchange, export, simulate client. - @flow-as-code/cli: the flow-cli binary: lint, render, codegen, synth, emit, studio, diff, export, simulate. - @flow-as-code/studio: the visual editor over FlowDoc, served locally by flow-cli studio. - @flow-as-code/cdk: CDK token binding (TokenBinder) and the FlowSet construct. - @flow-as-code/tf: the Terraform and OpenTofu emitter: FlowDoc to .tf and .tftpl files. ## Format and design - [FlowDoc, the interchange format](https://flow-as-code.dev/docs/flowdoc-spec/): The JSON document every tool in the set reads and writes: its structure, the ${cdref:type:name} reference tokens, the invariants synth and codegen preserve, and how the format is versioned. - [Studio design](https://flow-as-code.dev/docs/studio-design/): How the visual editor is put together: the canvas over FlowDoc, the bidirectional sync between canvas and typed TypeScript, the local bridge that flow-cli studio serves, and the in-app export targets. - [Terraform emitter design](https://flow-as-code.dev/docs/terraform-emitter/): What the emitter writes for a set of flows, the rules it holds to (no literal ARNs, no provider or backend blocks), and the corrections that running it against OpenTofu produced. - [The hosted read-only studio demo](https://flow-as-code.dev/docs/hosted-demo/): How the browser demo is built, what the demo build swaps out, how it is deployed, and the static and runtime checks that prove it makes no network request after its own assets load. ## Worked example - [Promote one flow across two environments](https://flow-as-code.dev/docs/promote-across-environments/): A walkthrough you can run: one FlowDoc reaching a dev and a prod environment down both the Terraform and the CDK path, with no per-environment ARN table, and what the example does not claim. ## Package references - [flow-cli command reference](https://flow-as-code.dev/docs/package-cli/): Every flow-cli command with its flags, input and output conventions, and exit codes: lint, render, codegen, synth, emit, diff, export, simulate, and studio. - [@flow-as-code/core, the engine](https://flow-as-code.dev/docs/package-core/): The package the others build on: typed builder and synthesizer, codegen, lint, FlowDoc interchange, export from a live Amazon Connect instance, and the simulate scenario runner and its limits. - [@flow-as-code/cdk, the CDK binding](https://flow-as-code.dev/docs/package-cdk/): The TokenBinder interface that maps reference names to construct attributes, the FlowSet construct that turns a directory of FlowDocs into Connect resources, and the peer dependencies both need. - [@flow-as-code/tf, the HCL emitter](https://flow-as-code.dev/docs/package-tf/): Calling the emitter, the .tf and .tftpl files it writes, how references become template variables, how escaping works, and what an incomplete address map does to the output. - [@flow-as-code/studio, the visual editor](https://flow-as-code.dev/docs/package-studio/): The save gate every write path runs through, the demotion invariant that stops a canvas gesture from quietly losing typed authoring, the export targets, and the read-only stores. ## Contract and process - [The conformance suite](https://flow-as-code.dev/docs/conformance/): The cross-language contract a second implementation has to reproduce: the fixture families for schema, flow language, lint, roundtrip, materialize, emit, export and simulate. - [Contributing](https://flow-as-code.dev/docs/contributing/): How work is done in this repository: getting set up, the rules that are not negotiable, why every test has to be able to fail, and the commit, docs and licensing conventions. ## Decisions - [ADR-0001: Defer jsii](https://flow-as-code.dev/docs/adr-defer-jsii/): The decision not to publish the CDK package through jsii until the builder API stabilizes, and the type-system features the builder would have to give up to adopt it early. - [ADR-0002: Error branches are required config properties](https://flow-as-code.dev/docs/adr-error-branches/): Why an unwired error branch is caught as a type error through required config properties rather than a state-threaded fluent builder, and what that keeps codegen output readable. - [ADR-0003: Synth preserves declaration order](https://flow-as-code.dev/docs/adr-action-ordering/): Why synth emits actions in the order the author declared them rather than in graph reachability order, and what that buys the codegen round trip. - [ADR-0004: Prior art, and why this is not Amazon's L2 CDK library](https://flow-as-code.dev/docs/adr-prior-art-aws-l2-cdk-library/): The technical difference against the L2 CDK construct library the AWS Contact Center blog described: references that stay ${cdref:type:name} tokens through to deploy time rather than ARNs written in by a centralized mapping table, and a Terraform path alongside the CDK one. ## Optional - [llms-full.txt](https://flow-as-code.dev/llms-full.txt): every page above as one markdown file, for a model that would rather fetch once than crawl. - [Conformance fixtures](https://github.com/flow-as-code/flow-as-code/tree/main/conformance): the cross-language contract, as data.