Skip to main content
Selectors are Ctrlplane’s powerful filtering system for targeting resources, environments, and deployments. They allow dynamic, rules-based matching instead of static assignments.

Why Selectors?

Traditional deployment tools require manually assigning resources to environments. Ctrlplane uses selectors for dynamic matching:

Without Selectors (Traditional)

Production Environment:
  ├─ Manually add: cluster-1
  ├─ Manually add: cluster-2
  └─ Manually add: cluster-3

New cluster added? Manually add it to production.

With Selectors (Ctrlplane)

Production Environment:
  └─ Selector: metadata.environment == "production"

New cluster with metadata.environment = "production"?
Automatically included in production!

Selector Types

Ctrlplane supports several types of selectors:
  1. Metadata Selector - Match on resource metadata
  2. Kind Selector - Match on resource kind
  3. Identifier Selector - Match on resource identifier
  4. Name Selector - Match on resource/environment name
  5. CEL Selector - Complex expressions using CEL (Common Expression Language)
  6. Composite Selectors - Combine selectors with AND/OR logic

Metadata Selector

Match resources based on metadata key-value pairs using CEL expressions.

Simple Equality

resourceSelector: resource.metadata["environment"] == "production"
Matches resources where metadata.environment === "production".

Supported Operators

equals

Exact match:
resourceSelector: resource.metadata["region"] == "us-east-1"

not_equals

Does not match:
resourceSelector: resource.metadata["deprecated"] != "true"

contains

Value contains substring:
resourceSelector: resource.identifier.contains("prod")
Matches: prod-cluster-1, k8s-prod, production-server.

matches (Regex)

Regular expression match:
resourceSelector: resource.identifier.matches("^prod-.*-[0-9]+$")
Matches: prod-cluster-1, prod-server-42.

exists

Key exists with any value:
resourceSelector: has(resource.metadata["team"])
Matches any resource with a team metadata key.

not_exists

Key does not exist:
resourceSelector: "!has(resource.metadata[\"deprecated\"])"

in

Value is in a list:
resourceSelector: resource.metadata["region"] in ["us-east-1", "us-east-2", "us-west-1"]

not_in

Value is not in a list:
resourceSelector: "!(resource.metadata[\"status\"] in [\"deprecated\", \"decommissioned\"])"

Kind Selector

Match resources by their kind field.
resourceSelector: resource.kind == "KubernetesCluster"
Common Use Cases:
  • Kubernetes-only deployments: resource.kind == "KubernetesCluster"
  • VM-only deployments: resource.kind == "VirtualMachine"
  • Exclude certain kinds: resource.kind != "DeprecatedResource"

Identifier Selector

Match resources by their identifier.
resourceSelector: resource.identifier.contains("prod")
Use Cases:
  • Match specific naming patterns
  • Filter by identifier prefix/suffix
  • Regex matching on identifiers

Name Selector

Match by the resource or environment name field.
# In policy selectors
environments: environment.name == "Production"
Use Cases:
  • Policy selectors targeting specific environments
  • Matching resources by name patterns

Composite Selectors (AND/OR)

Combine multiple conditions with boolean logic using CEL operators.

AND Logic

All conditions must match:
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["region"] == "us-east-1"
Matches: Resources with BOTH environment=production AND region=us-east-1.

OR Logic

Any condition can match:
resourceSelector: >-
  resource.metadata["region"] == "us-east-1" ||
  resource.metadata["region"] == "us-west-2"
Matches: Resources in EITHER us-east-1 OR us-west-2.

Nested Logic

Combine AND and OR:
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  (resource.metadata["region"] == "us-east-1" ||
   resource.metadata["region"] == "us-west-2")
Matches: environment=production AND (region=us-east-1 OR region=us-west-2).

CEL Expressions

Ctrlplane uses CEL (Common Expression Language) for all selectors:
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["tier"] == "critical"

CEL Basics

Field Access:
  • resource.metadata["environment"] - Access metadata field
  • resource.kind - Access kind field
  • resource.name - Access name field
  • resource.identifier - Access identifier field
Operators:
  • ==, != - Equality
  • &&, || - Logical AND/OR
  • ! - Logical NOT
  • <, >, <=, >= - Comparison
  • in - List membership
  • .matches() - Regex match
Examples:
# Production OR Staging
resourceSelector: resource.metadata["environment"] in ["production", "staging"]

# Critical tier in production
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["tier"] == "critical"

# Not deprecated
resourceSelector: >-
  !has(resource.metadata["deprecated"]) ||
  resource.metadata["deprecated"] != "true"

# Regex match on identifier
resourceSelector: resource.identifier.matches("^prod-cluster-[0-9]+$")

# Complex nested logic
resourceSelector: >-
  (resource.metadata["environment"] == "production" &&
   resource.metadata["region"] in ["us-east-1", "us-west-2"]) ||
  (resource.metadata["environment"] == "staging" &&
   resource.metadata["region"] == "us-east-1")

CEL Best Practices

Do:
  • ✅ Use CEL for complex nested logic
  • ✅ Keep expressions readable with line breaks
  • ✅ Test selectors before applying
  • ✅ Reference the CEL Reference for syntax
Avoid:
  • ❌ Overly complex expressions that are hard to understand
  • ❌ Expressions that might accidentally match wrong resources

Selector Use Cases

Environment Resource Selectors

Define which resources belong to an environment:
# Production environment
type: Environment
name: Production
resourceSelector: resource.metadata["environment"] == "production"
# Multi-region production
type: Environment
name: Production US East
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["region"] == "us-east-1"

Deployment Resource Selectors

Limit which resources a deployment can target:
# Kubernetes-only deployment
type: Deployment
name: Container Service
resourceSelector: resource.kind == "KubernetesCluster"
# Region-specific deployment
type: Deployment
name: US-Only Service
resourceSelector: resource.metadata["region"].matches("^us-.*")

Policy Selectors

Target policies to specific deployments/environments/resources:
type: Policy
name: Production Approval Required
selectors:
  - environments: environment.name == "Production"
    deployments: deployment.metadata["critical"] == "true"
rules:
  - anyApproval:
      minApprovals: 2
This policy applies to critical deployments going to production.

Testing Selectors

Via CLI

Test a selector against your resources:
ctrlc api get resources \
  --workspace {workspaceId} \
  --selector 'resource.metadata["environment"] == "production"'
Returns all resources matching the selector.

Via Web UI

Most selector configuration screens have a “Test Selector” or “Preview Resources” button that shows which resources match.

Common Selector Patterns

Pattern 1: Environment-Based

resourceSelector: resource.metadata["environment"] == "production"
Use Case: Standard environment separation (dev/staging/prod).

Pattern 2: Region-Based

resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["region"] == "us-east-1"
Use Case: Multi-region deployments, gradual regional rollout.

Pattern 3: Team-Based

resourceSelector: resource.metadata["team"] == "platform"
Use Case: Team-specific resources and deployments.

Pattern 4: Tier-Based

resourceSelector: resource.metadata["tier"] in ["critical", "high-priority"]
Use Case: SLA-based resource grouping.

Pattern 5: Canary

resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["canary"] == "true"
Use Case: Canary deployment pattern.

Pattern 6: Percentage-Based (using identifier)

resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.identifier.matches(".*[02468]$")
Use Case: Target resources with even-numbered identifiers (50% rollout).

Best Practices

Metadata Schema Design

Design your resource metadata with selectors in mind: Good Metadata Schema:
# Recommended metadata keys
metadata:
  environment: production | staging | development
  region: us-east-1 | us-west-2 | eu-west-1
  zone: us-east-1a | us-east-1b | ...
  tier: critical | high | standard | low
  team: platform | product | data
  canary: "true" | "false"
Why Good:
  • Consistent key names
  • Enumerated values (not free-form)
  • Multiple dimensions for targeting
  • Clear, hierarchical organization

Selector Simplicity

Prefer Simple Selectors:
resourceSelector: resource.metadata["environment"] == "production"
Over Complex Ones:
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["region"].startsWith("us-") &&
  resource.metadata["tier"] == "critical" &&
  !has(resource.metadata["deprecated"])
Simple selectors are:
  • Easier to understand
  • Less error-prone
  • More performant

Document Complex Selectors

If you must use complex selectors, document them:
type: Environment
name: Production Critical
description: >-
  Targets production resources in US regions that are marked 
  critical tier and not deprecated
resourceSelector: >-
  resource.metadata["environment"] == "production" &&
  resource.metadata["region"].startsWith("us-") &&
  resource.metadata["tier"] == "critical" &&
  !has(resource.metadata["deprecated"])

Test Before Applying

Always test selectors before using them:
  1. Use the query API to see matched resources
  2. Verify count matches expectations
  3. Check for unexpected matches
  4. Test in lower environment first

Avoid Over-Matching

Be specific to avoid accidentally matching wrong resources: Too Broad:
resourceSelector: resource.identifier.contains("prod")
Might match: prod-cluster, product-server, reproduction-env. Better:
resourceSelector: resource.identifier.matches("^prod-.*")
Only matches identifiers starting with prod-.

Troubleshooting

Selector matches too many resources

  • Make selector more specific (add conditions)
  • Use AND instead of OR
  • Add negation conditions
  • Check resource metadata for unexpected values

Selector matches too few resources

  • Check metadata key names match exactly (case-sensitive)
  • Verify resources have the expected metadata
  • Use OR logic if resources vary
  • Test with simpler selector first

Selector matches nothing

  • Verify selector syntax is correct
  • Check resources exist with expected metadata
  • Test each condition independently
  • Review resource metadata in UI

CEL expression errors

Advanced Topics

Selector Evaluation Order

When multiple selectors apply (e.g., environment + deployment):
  1. Environment selector filters resources
  2. Deployment selector (if present) filters further
  3. Final set is intersection of both

Selector Performance

Selectors are evaluated:
  • When resources are created/updated
  • When environments/deployments are created/updated
  • When querying resources
Performance Tips:
  • Simple selectors are faster than complex ones
  • Metadata equality checks are very fast
  • Regex matching is slower
  • CEL expressions have some overhead

Selector Caching

Ctrlplane caches selector evaluation results:
  • Cache invalidated on resource/metadata changes
  • Improves performance for repeated queries
  • No manual cache management needed

Next Steps