Workspace-specific items
Workspace-specific items let you store different versions of resources, variables, triggers, folders, and workspace settings per workspace (dev / staging / prod). The CLI transforms file paths so that each workspace has its own namespaced files locally while keeping clean base paths in the Windmill workspace itself.
Using workspaces: with multiple entries (one per environment, each with its own
gitBranch) corresponds to stage 4 of the
collaboration and deployment stages
guide. The single-workspace form of workspaces: is used starting at
stage 3.
This replaces the older split between gitBranches (multi-branch) and environments
(single-branch). Both are now a single workspaces: key — see
Migrating from gitBranches / environments.
How it works
When a file matches a pattern in your wmill.yaml configuration, the CLI inserts the
workspace name into the local file path:
- Local files:
database.dev.resource.yaml,database.prod.resource.yaml - Windmill workspace:
database.resource.yaml(clean base path)
Each workspace has its own version of the same logical resource. In practice, multiple
workspace-specific files usually coexist in the repository (e.g. database.dev.resource.yaml
and database.prod.resource.yaml side by side) — by design when one git branch hosts
multiple workspaces, or as a result of merging branches when each workspace has its own
branch. The CLI only reads the files matching the current workspace and ignores the others.
Configuration
Workspace-specific items are declared inside a workspaces: entry, either per workspace
under specificItems, or shared across every workspace under commonSpecificItems.
workspaces:
dev:
baseUrl: https://dev.windmill.dev
overrides:
skipSecrets: true
specificItems:
resources:
- "u/alex/config/**"
variables:
- "u/alex/env_*"
triggers:
- "u/alex/kafka_*"
folders:
- "f/env_*"
settings: true
prod:
baseUrl: https://app.windmill.dev
gitBranch: main # workspace "prod" lives on git branch "main"
overrides:
skipSecrets: false
specificItems:
resources:
- "u/alex/config/**"
variables:
- "u/alex/env_*"
folders:
- "f/env_*"
settings: true
# Items that are workspace-specific across ALL workspaces
commonSpecificItems:
resources:
- "u/alex/config/**"
variables:
- "u/alex/database_*"
folders:
- "f/env_*"
settings: true
The workspaces key is the map key (dev, prod, …) and is also the suffix inserted into
file names on disk. gitBranch and workspaceId default to that key — only set them when
they differ.
Resolving the current workspace
wmill sync pull and wmill sync push pick the workspace in this order:
--workspace <name>— explicit override, looks up the entry by key.- Current git branch — the first entry whose effective
gitBranchmatchesgit rev-parse --abbrev-ref HEAD. - No match — top-level sync options are used as-is, no workspace-specific transform.
One git branch per workspace
Each workspace has its own git branch. The CLI detects the current branch automatically and applies the matching entry.
git checkout main
wmill sync pull
# Uses workspace "prod" (gitBranch: main)
# Creates: u/alex/config/database.prod.resource.yaml
git checkout dev
wmill sync pull
# Uses workspace "dev"
# Creates: u/alex/config/database.dev.resource.yaml
Multiple workspaces on one git branch
All workspaces live on the same branch and you pick the target with --workspace.
wmill sync pull --workspace dev
# Creates: u/alex/config/database.dev.resource.yaml
wmill sync pull --workspace prod
# Creates: u/alex/config/database.prod.resource.yaml
wmill sync push --workspace staging
No git checkout is needed — all workspace-specific files coexist on the same branch.
--env and --branch--branch and --env are still accepted on sync commands but are deprecated — they print a
one-time warning and resolve the same way --workspace does. Update any scripts or CI jobs
to use --workspace instead.
File path transformation
Transform logic
Pull (Windmill workspace → local):
u/alex/database.resource.yaml→u/alex/database.prod.resource.yamlu/alex/orders.kafka_trigger.yaml→u/alex/orders.prod.kafka_trigger.yamlf/env_staging/folder.meta.yaml→f/env_staging/folder.prod.meta.yamlsettings.yaml→settings.prod.yaml
Push (local → Windmill workspace):
u/alex/database.dev.resource.yaml→u/alex/database.resource.yamlu/alex/orders.dev.kafka_trigger.yaml→u/alex/orders.kafka_trigger.yamlf/env_staging/folder.dev.meta.yaml→f/env_staging/folder.meta.yamlsettings.dev.yaml→settings.yaml
The suffix is the workspace name (the key in workspaces:). In migrated configs where
the workspace name equals the old branch name, existing files keep working unchanged.
Resource files
Resources can include associated files (certificates, config files, etc.) alongside their YAML definitions. These follow the same transformation:
- Base file:
u/alex/certificate.resource.file.pem - Workspace-specific:
u/alex/certificate.dev.resource.file.pem
When a resource YAML file is marked as workspace-specific, all associated resource files are automatically treated the same way.
Supported file types
- Variables:
*.variable.yaml - Resources:
*.resource.yamland resource files (*.resource.file.*) - Triggers:
*.kafka_trigger.yaml,*.http_trigger.yaml,*.websocket_trigger.yaml,*.nats_trigger.yaml,*.postgres_trigger.yaml,*.mqtt_trigger.yaml,*.sqs_trigger.yaml,*.gcp_trigger.yaml - Schedules:
*.schedule.yaml - Folders:
folder.meta.yamlfiles within folder directories - Settings:
settings.yaml(workspace settings file)
Pattern matching
Patterns support standard glob syntax:
*matches any characters within a path segment**matches any characters across path segmentsu/alex/database_*matchesu/alex/database_config,u/alex/database_url, etc.f/environments/**matches all files underf/environments/recursively
Common specific items
Items that should be workspace-specific across all workspaces can be declared once under
commonSpecificItems:
workspaces:
commonSpecificItems:
variables:
- "u/alex/database_*"
- "f/config/**"
resources:
- "u/alex/api_keys/**"
- "f/environments/**"
triggers:
- "u/alex/kafka_*"
- "f/streaming/**"
folders:
- "f/env_*"
settings: true
Per-workspace specific items
If some resources only exist in certain workspaces, define different patterns per workspace
instead of using commonSpecificItems:
workspaces:
prod:
specificItems:
variables:
- "u/alex/prod_*"
resources:
- "u/alex/production/**"
triggers:
- "u/alex/prod_kafka_*"
folders:
- "f/prod_config"
settings: true
dev:
specificItems:
variables:
- "u/alex/dev_*"
resources:
- "u/alex/development/**"
triggers:
- "u/alex/dev_kafka_*"
folders:
- "f/dev_config"
settings: true
Here, prod_kafka_* triggers only get the workspace suffix on prod — they don't exist in
dev, so there's no need to mark them there. Most setups use commonSpecificItems since
the same resources typically exist across all workspaces.
Name safety
Workspace names containing certain characters are automatically sanitized for filesystem safety:
- Unsafe characters:
/ \ : * ? " < > | . - Replacement: All unsafe characters are replaced with
_ - Warning: The CLI shows a clear warning when sanitization occurs
Warning: Branch name "feature/api-v2.1" contains filesystem-unsafe characters (/ \ : * ? " < > | .)
and was sanitized to "feature_api-v2_1". This may cause collisions with other similarly named branches.
Prefer simple workspace keys (dev, staging, prod) to avoid collisions.
Best practices
- Start broad: Use
commonSpecificItemsfor widely-used resources - Be specific: Target exact paths rather than overly broad patterns
- Group logically: Organize patterns by team, workspace, or function
- Define patterns early: Establish patterns before team members start using them
- Test locally: Verify workspace-specific behavior works correctly before CI/CD integration
Troubleshooting
Files not being detected as workspace-specific
- Check patterns: Ensure your glob patterns match the file paths exactly
- Verify file types: Only the types listed above are supported
- Pattern testing: Use tools like globster.xyz to test your patterns
Files syncing to the wrong workspace
- Check config: Ensure your
workspaces:entry is correct - Verify current context: Make sure you're on the expected git branch or using the right
--workspaceflag - Configuration precedence: CLI flags override configuration file settings
Git sync integration
When Git sync is configured, workspace-specific items work seamlessly with your Git repository setup. Git sync pushes changes to the correct workspace-specific files based on the resolved workspace.
-
One git branch per workspace: each Windmill workspace's
git_repositoryresource points to a different branch. Git sync detects the branch and applies the matchingworkspaces:entry automatically.- Production workspace:
git_repositorypointing torepoXonmainbranch- Changes to
database.resource.yaml→ pushed asdatabase.prod.resource.yaml
- Changes to
- Development workspace:
git_repositorypointing torepoXondevbranch- Changes to
database.resource.yaml→ pushed asdatabase.dev.resource.yaml
- Changes to
- Production workspace:
-
Multiple workspaces on one git branch: all Windmill workspaces point to the same branch. Set the workspace name in the Git sync advanced settings so Git sync applies the matching
workspaces:entry.
Related documentation
- CLI sync - Main sync operations and configuration
- Git sync settings - Managing sync configuration
- Git sync - Backend Git integration