Skip to main content
Version selector rules filter which deployment versions are allowed to deploy to matching environments. Use them to restrict production to stable releases, enforce naming conventions, or block specific versions.

Overview

Why Use Version Selectors?

Version selector rules help you:
  • Enforce release channels - Only stable versions in production
  • Block bad versions - Prevent known-bad releases from deploying
  • Naming conventions - Require specific version formats
  • Feature flags - Control rollout of experimental features
  • Context-aware filtering - Use environment, resource, or deployment data to make dynamic version decisions

Configuration

resource "ctrlplane_policy" "production_stable" {
  name     = "Production Stable Only"
  selector = "environment.name == 'production'"

  version_selector {
    selector    = "!version.tag.contains('-rc')"
    description = "Only stable versions (no release candidates)"
  }
}

Properties

versionSelector.selector
string | object
required
A CEL expression (string) or JSON selector (object) to match allowed versions. CEL expressions have access to version, environment, resource, and deployment variables, enabling context-aware version filtering.
versionSelector.description
string
Human-readable explanation of the rule. Shown to users when a version is blocked.

CEL Expression Variables

When using CEL expressions, you have access to the following variables:
VariableTypeDescription
versionmapThe deployment version being evaluated
environmentmapThe target environment
resourcemapThe target resource
deploymentmapThe deployment

Version Fields

FieldTypeDescription
version.tagstringVersion tag (e.g., “v1.2.3”)
version.metadatamapCustom metadata on the version
version.createdAtstringWhen the version was created
version.statusstringVersion status (e.g., “ready”)

Environment Fields

FieldTypeDescription
environment.namestringEnvironment name
environment.metadatamapCustom metadata

Resource Fields

FieldTypeDescription
resource.namestringResource name
resource.metadatamapCustom metadata

Deployment Fields

FieldTypeDescription
deployment.namestringDeployment name
deployment.metadatamapCustom metadata
The CEL environment includes standard extensions (string functions, math, etc.) and all entity fields are accessible as map keys.

Common Patterns

Stable Versions Only

Block pre-release versions from production:
{
  "name": "Production Stable",
  "selector": "environment.name == 'production'",
  "rules": [
    {
      "versionSelector": {
        "selector": "!version.tag.contains('-')",
        "description": "No pre-release versions (no hyphens in tag)"
      }
    }
  ]
}

Semantic Version Pattern

Require semantic versioning format:
{
  "versionSelector": {
    "selector": "version.tag.matches('^v[0-9]+\\\\.[0-9]+\\\\.[0-9]+$')",
    "description": "Must be semantic version (vX.Y.Z)"
  }
}

Release Channel by Metadata

Use version metadata for release channels:
[
  {
    "name": "Production Channel",
    "selector": "environment.name == 'production'",
    "rules": [
      {
        "versionSelector": {
          "selector": "version.metadata['channel'] == 'stable'",
          "description": "Only stable channel versions"
        }
      }
    ]
  },
  {
    "name": "Staging Channels",
    "selector": "environment.name == 'staging'",
    "rules": [
      {
        "versionSelector": {
          "selector": "version.metadata['channel'] in ['stable', 'beta']",
          "description": "Stable and beta channels allowed"
        }
      }
    ]
  }
]

Major Version Restriction

Restrict major version changes:
{
  "versionSelector": {
    "selector": "version.tag.startsWith('v2.')",
    "description": "Only v2.x versions allowed"
  }
}

Context-Aware Version Filtering

Use environment or resource data to dynamically filter versions. This is uniquely powerful because the selector has access to all four entity types:
{
  "name": "Region-Specific Versions",
  "selector": "environment.name == 'production'",
  "rules": [
    {
      "versionSelector": {
        "selector": "resource.metadata['region'] != 'us-east-1' || version.metadata['us_east_certified'] == 'true'",
        "description": "US-East-1 requires certified versions"
      }
    }
  ]
}

Branch-Based Filtering

Only deploy versions from the main branch:
{
  "versionSelector": {
    "selector": "version.metadata['branch'] == 'main'",
    "description": "Only deploy versions from main branch"
  }
}

Feature Flag Versions

Control feature rollout by version metadata and resource:
{
  "name": "New UI Rollout",
  "selector": "environment.name == 'production'",
  "rules": [
    {
      "versionSelector": {
        "selector": "resource.metadata['region'] == 'us-east-1' || !has(version.metadata['feature_new_ui']) || version.metadata['feature_new_ui'] != 'true'",
        "description": "New UI only enabled for us-east-1"
      }
    }
  ]
}

JSON Selector Format

As an alternative to CEL expressions, you can use JSON selectors that match against the version object:
{
  "versionSelector": {
    "selector": {
      "matchExpression": [
        {
          "key": "tag",
          "operator": "DoesNotContain",
          "value": "-rc"
        }
      ]
    },
    "description": "Only stable versions (no release candidates)"
  }
}

JSON Selector Operators

OperatorDescriptionExample
EqualsExact matchtag Equals "v1.0.0"
NotEqualsNot equaltag NotEquals "v1.0.0"
InValue in listtag In ["v1.0.0", "v1.0.1"]
NotInValue not in listtag NotIn ["v1.0.0"]
ContainsString containstag Contains "beta"
DoesNotContainString does not containtag DoesNotContain "rc"
StartsWithString starts withtag StartsWith "v2."
EndsWithString ends withtag EndsWith "-stable"
MatchesRegex matchtag Matches "^v[0-9]+"
ExistsField existsmetadata.approved Exists
DoesNotExistField does not existmetadata.blocked DoesNotExist
JSON selectors only match against the version object. For cross-entity filtering (e.g., using environment or resource data), use CEL expressions instead.

Best Practices

Environment Guidelines

EnvironmentVersion Policy
DevelopmentAllow all versions
QAAllow all or beta+
StagingStable and beta
ProductionStable only

Recommendations

  • ✅ Use description to explain why versions are restricted
  • ✅ Prefer CEL expressions for context-aware filtering (access to environment, resource, deployment)
  • ✅ Use metadata for release channels instead of parsing tags
  • ✅ Document blocked versions with links to issues
  • ✅ Test selectors in lower environments first
  • ✅ Start permissive and tighten over time

Anti-Patterns

  • ❌ Overly complex regex patterns
  • ❌ Blocking without documentation
  • ❌ Inconsistent version tagging conventions
  • ❌ Forgetting to update blocked version lists

Next Steps