Skip to main content

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.

Multi-workspace setups are stage 4 of the collaboration guide

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:

  1. --workspace <name> — explicit override, looks up the entry by key.
  2. Current git branch — the first entry whose effective gitBranch matches git rev-parse --abbrev-ref HEAD.
  3. 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.

Migrating from --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.yamlu/alex/database.prod.resource.yaml
  • u/alex/orders.kafka_trigger.yamlu/alex/orders.prod.kafka_trigger.yaml
  • f/env_staging/folder.meta.yamlf/env_staging/folder.prod.meta.yaml
  • settings.yamlsettings.prod.yaml

Push (local → Windmill workspace):

  • u/alex/database.dev.resource.yamlu/alex/database.resource.yaml
  • u/alex/orders.dev.kafka_trigger.yamlu/alex/orders.kafka_trigger.yaml
  • f/env_staging/folder.dev.meta.yamlf/env_staging/folder.meta.yaml
  • settings.dev.yamlsettings.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.yaml and 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.yaml files 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 segments
  • u/alex/database_* matches u/alex/database_config, u/alex/database_url, etc.
  • f/environments/** matches all files under f/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 commonSpecificItems for 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

  1. Check patterns: Ensure your glob patterns match the file paths exactly
  2. Verify file types: Only the types listed above are supported
  3. Pattern testing: Use tools like globster.xyz to test your patterns

Files syncing to the wrong workspace

  1. Check config: Ensure your workspaces: entry is correct
  2. Verify current context: Make sure you're on the expected git branch or using the right --workspace flag
  3. 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_repository resource points to a different branch. Git sync detects the branch and applies the matching workspaces: entry automatically.

    • Production workspace: git_repository pointing to repoX on main branch
      • Changes to database.resource.yaml → pushed as database.prod.resource.yaml
    • Development workspace: git_repository pointing to repoX on dev branch
      • Changes to database.resource.yaml → pushed as database.dev.resource.yaml
  • 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.