Flows TF Provider
The Flows TF Provider can be used with OpenTofu and Terraform to manage Flows (yes, Flows-as-Code!), app installations, secrets, and more.
You can find installation and basic usage instructions in the GitHub repository and resource documentation on the OpenTofu registry.
When using with Terraform (as opposed to OpenTofu), you will have to provide the full registry path:
terraform { required_providers { flows = { source = "registry.opentofu.org/spacelift-io/flows" } }}Managing Flows as Code
Section titled “Managing Flows as Code”Whether you want to version control your flows, have a code-review driven change management process, deploy them across multiple environments, or generate them programmatically, the Flows TF Provider can help you achieve that.
Flows themselves have a YAML representation, which you can export from the UI. Without any blocks selected, click cmd+c to copy the entire flow (or with blocks selected, to copy just those), you can then paste that into a yaml file.
Here’s an example of such a Flow (the #1 sample flow):
blocks: - name: Sample Endpoint type: coreBlock: httpEndpoint position: [-50, 82] config: path: /hello/{name} methods: - GET audience: world inputs: default: links: - block: Sleep output: default config: statusCode: 200 body: !expr '`Hello, ${outputs.sampleEndpoint.params.name}`' - name: Sleep type: coreBlock: sleep position: [-50, 255] inputs: default: links: - block: Sample Endpoint output: requests config: sleep: 5notes: - body: |- # Simple Webhook Handler
You can see that the **HTTP Endpoint** block produces events on its `requests` output, and expects a response to arrive at its input.
To test this Flow, first click on the **Sample Endpoint** block, then click on the copy button next to the **Path** field. You can navigate to the copied URL using your browser, or curl it.
Once you do that and get a response, you will also see events appear on the canvas next to various outputs. Click on an output to see the events it produced!
You can **re-emit** those events, in order to replay parts of your flow - great for debugging, or just building up your flow piece by piece! position: [273, 13] style: width: 400 height: 380 color: '#18181b'This is pretty self-explanatory. For config fields, you can just input raw values, or provide expressions using the !expr tag.
It becomes slightly more complex if you have apps. Here you can see a Flow with app blocks used:
appInstallations: slack: appName: Slack appVersion: 0.2.2 id: 019a4a1d-3494-758a-9df9-67d6e5f4660bblocks: - name: Mentions type: appBlock: block: appMentionSubscription appInstallation: slack position: [116, 0] - name: Is Hello Command description: Checks if the mention contains a hello command type: coreBlock: condition position: [0, 160] inputs: default: links: - block: Mentions output: default config: condition: !expr /^<@U\w+>\s+hello$/i.test(outputs.mentions.text.trim()) - name: Hello Response description: Sends a hello message to the user type: appBlock: block: sendTextMessage appInstallation: slack position: [0, 293] inputs: default: links: - block: Is Hello Command output: then config: channelId: !expr outputs.mentions.channel text: !expr '`Hello <@${outputs.mentions.user}>!`' threadTs: !expr outputs.mentions.thread_ts || outputs.mentions.tshere you can see that the type of app blocks refers back to the installation they are related to, while an initial appInstallations section describes the apps used, their versions, and installation IDs.
Importantly, the yaml representation only manages the “configuration layer” of the Flow. It does not include e.g. lifecycle confirmation.
Managing Flows with the TF Provider
Section titled “Managing Flows with the TF Provider”With the Flows TF Provider, you can use the flows_flow resource to create and update Flows. Additionally, you are able to parameterize the app installations (so you don’t have to include the IDs in the yaml file):
resource "flows_flow" "example" { project_id = "your-project-id" name = "my-flow" definition = file("${path.module}/flow.yaml")
app_installation_mapping = { my_app = "app-installation-id" }}Moreover, if you have blocks with a lifecycle, you are able to confirm them using the flows_entity_lifecycle_confirmation:
resource "flows_entity_lifecycle_confirmation" "example" { entity_id = flows_flow.example.blocks["my_entity"].id}Changing Block Names
Section titled “Changing Block Names”Blocks are uniquely identified by their names. This means that if you just change a block name, it will be deleted and recreated - for most blocks this is fine, but you will lose e.g. the event history of that block. Additionally, it will be problematic for blocks that manage external resources (like AWS Resource blocks).
To rename a block without losing its identity, you can use the alternativeLookupStrategy field. Here’s an example of how to use it by referring to the old name of the block:
blocks:- name: New Block Name alternativeLookupStrategy: name: Old Block Name type: appBlock: block: appMentionSubscription appInstallation: slack position: [116, 0]Alternatively, you can also directly refer to the block ID:
blocks:- name: New Block Name alternativeLookupStrategy: id: 019be5ca-3832-717a-b5d7-dfe4bc19569a type: appBlock: block: appMentionSubscription appInstallation: slack position: [116, 0]Reference
Section titled “Reference”See the Flow Definition Reference for complete YAML schema documentation.