Flows as code: Git, plan and apply, and the editor stays
Etlworks 10.1.0 keeps flows, connections, formats, macros and schedules in Git as readable files, and deploys them with plan and apply from the app or from CI.
Visual integration tools have always been weak at what happens after the flow is built. You export a file nobody can read, import it into production, and hope nobody changed anything there in the meantime. Etlworks 10.1.0 puts flows, connections, formats, macros and schedules in Git as readable files, and deploys them with plan and apply. The visual editor does not go anywhere; Git is where the result lives.
Files you can review
A project is a folder: a manifest, etlworks.json, and one file per object.
etlworks.json
flows/load-orders.json
flows/load-orders/source-query.sql
connections/snowflake.json
schedules/nightly.json
environments/prod.json
We made a few decisions so that a pull request reads like code. Objects are identified by name and type, never by internal IDs, so the same project deploys to any tenant or instance. References between objects are by name. Code of 20 lines or more goes into its own file, so a changed query shows as a line diff. There are no IDs, timestamps or "exported by" fields, which means an export of unchanged flows is byte-identical and produces an empty diff. Canvas layout lives in one place, so moving a box is a one-line change.
Plan, then apply
A deploy is project-plan, then project-apply. The plan prints one line per object (create, update, adopt, keep, unchanged, delete) and changes nothing. An object somebody edited directly in the target since its last deploy shows as update (drift), so you see what you are about to overwrite before you do it.
The plan ends with a hash. Apply with that hash and Etlworks refuses if anything changed since you reviewed it. Apply runs in one transaction under a per-project lock, and skips unchanged objects entirely: no new revision, no webhook event. A schedule created by a deploy starts disabled unless the environment says otherwise, because a production schedule that fires by accident is worse than one you forgot to turn on.
Secrets stay out of Git
Connections export without passwords by default. Each environment gets its own values from a file in Git, environments/prod.json, for hosts, warehouses, flow variables and schedules, and from values stored in Etlworks for the things that should never be committed:
project-env-set analytics connection Snowflake password value=... secret=true
Encrypted credentials in the files are available too, but I would not start there.
Two ways to run it
From Etlworks. Add a Git Repository connection and select flows, then Manage in Git. Promotion is a branch, a review and a tag:
git-sync-in "Analytics repo" ref=main path=projects/analytics env=test dry-run=true
git-tag "Analytics repo" name=release-2026.11 ref=main
git-sync-in "Analytics repo" ref=release-2026.11 path=projects/analytics env=prod
A tag never moves, so production runs exactly what passed in test. Deploy on push is a Run CLI Script flow, a new flow type that runs CLI commands as a flow, started by your Git host's webhook. GitHub and Bitbucket signatures and GitLab tokens are verified before any command runs.
From CI. The new etlworks client needs Java 17 and an API key. Your pipeline checks out the repository, so Etlworks never holds Git credentials:
etlworks project plan ./projects/analytics --env prod --out plan.json
etlworks project apply ./projects/analytics --env prod --plan plan.json --yes
plan exits with 2 when there are changes, which is enough to gate a pipeline. The client page has complete GitHub Actions, GitLab CI and Azure DevOps examples.
When someone edits production anyway
They will. Objects managed in Git carry a badge, a source panel that shows the project, branch and commit, and a warning on save. Monitor → Git drift lists everything changed since its last deploy, and Compare with Git version shows the difference for one object. Export changes to a branch sends the edit back for review; Revert to Git version throws it away.
What it does not cover
A project holds flows and what they use. Webhooks, Integration Agents, templates, users and permissions stay out, and so do admin-level macros. A flow that a dynamic flow starts by name at run time is reported, not followed. Deleting what a project no longer contains (prune=true) and moving an object between projects need an Administrator.
If one environment and the built-in history are enough for you, ignore all of this. Nothing in the UI changes until an object is managed in Git.
The Git in Etlworks developer page and the Data Integration as Code guide cover the rest, from collision policies to troubleshooting.