BLOG/ENTERPRISE AUTOMATION
THEME
ENTERPRISE AUTOMATION

A private module registry for your org

Copy-pasted YAML is the new copy-pasted bash. Here's how to publish shared OrchStep workflows to a private registry under your own @scope and pin them with semver tags — so every team consumes the same versioned modules instead of a fork.

May 1, 2026 OrchStep Team 7 minROLE: Platform EngineerSCALE: Enterprise
RUNNABLE DEMO
Full source for this post: blog/org-module-registry
VIEW SOURCE

Once a few teams adopt a workflow tool, the same thing always happens: someone writes a good "deploy" workflow, three other teams copy it, and within a quarter you have four diverging versions of the same YAML. One has a fix the others don't. Another deleted the scan step. Copy-pasted YAML is just copy-pasted bash with better indentation.

The answer is the same one every language ecosystem landed on: a registry. Publish the shared workflow once, give it a version, and let teams depend on it by name and constraint instead of forking it. OrchStep does this with module registries scoped to your org.

Local for the demo, registry in production

The runnable demo uses local module folders so it works anywhere. The shape is exactly what you'd publish — a deploy-kit and a notify-kit your teams import:

orchstep.yml
name: org-module-registry

# For the demo these resolve to folders in this repo so it runs anywhere.
# In production you swap the source for a registry @scope (see below).
modules:
  - name: deploy
    source: "./modules/deploy-kit"
  - name: notify
    source: "./modules/notify-kit"

tasks:
  release:
    steps:
      - { name: ship, module: deploy, task: rollout, with: { service: "checkout", target: "staging" } }
      - { name: tell, module: notify, task: announce, with: { service: "checkout" } }

The consuming workflow's whole release surface is two module: calls. It doesn't know or care how rollout works internally — it depends on the contract, the same way your app depends on a library.

Point a registry at your repo

To go from local folders to shared modules, you declare a registry @scope and pin each module with a semver constraint. The registries: block maps a scope name to the repo that holds the modules:

LOCAL SOURCE (DEV)
modules:
  - name: deploy
    source: "./modules/deploy-kit"
  - name: notify
    source: "./modules/notify-kit"
REGISTRY @SCOPE (PROD)
registries:
  acme:
    url: github.com/acme/orchstep-modules

modules:
  - name: deploy
    source: "@acme/deploy-kit"
    version: "^1.2.0"
  - name: notify
    source: "@acme/notify-kit"
    version: "^0.4.0"

Same module: calls in tasks: — only the source resolution changes. Modules live in the registry repo at modules/@acme/<name>/ and are published as tags like deploy-kit/v1.2.0. The ^1.2.0 constraint means "the highest compatible 1.x," so a deploy-kit patch reaches every team on their next run without anyone editing their workflow. More: Modules.

Versioning is the whole point

The reason copy-paste rots is that there's no version to reason about — every fork is just "the YAML, as of whenever I copied it." Constraints fix that:

modules:
  - name: deploy
    source: "@acme/deploy-kit"
    version: "^1.2.0"   # highest 1.x — gets patches, not breaking changes

A team pins ^1.2.0 and gets bug fixes automatically while staying on a stable major. When deploy-kit ships a breaking v2.0.0, nobody is surprised — they opt in by bumping the constraint, on their own schedule. That's the difference between a dependency and a copy.

What you actually gained

ConcernCopy-pasted YAMLPrivate registry
Source of truthN forksone tagged repo
Getting a fixre-copy into each repo^1.2.0 picks it up
Breaking changesdiscovered in proda major bump you opt into
Who's on what versionnobody knowsthe pinned constraint
Ownershipdiffusethe registry repo's team

If only one team uses a workflow, don't build a registry — keep it local. This pays off the moment a second team wants the same thing, which is exactly when copy-paste starts. Publish it once, version it, and let version: constraints do the rest.

Where to go next

Two teams about to copy the same workflow? Publish it under an @scope, tag it v1.0.0, and have them depend on ^1.0.0 instead of forking it.

#PLATFORM-ENGINEERING#MODULES#REGISTRY#VERSIONING
Try it in two minutes — one binary, no signup.
curl -fsSL https://orchstep.dev/install.sh | sh

RELATED — ENTERPRISE AUTOMATION