This skill should be used when the user asks to "migrate rego", "rego v1", "v0 to v1", "upgrade rego", "opa fmt --rego-v1", "rego breaking changes", "rego compatibility", mentions Rego version migration, or encounters v0 syntax errors in OPA 1.0+. Provides Rego v0 to v1 migration patterns and tooling.
Guide for migrating Rego policies from v0 to v1 syntax. Rego v1 was released with OPA 1.0 (December 2024) and introduces mandatory syntax changes.
| Feature | v0 (Deprecated) | v1 (Required) |
|---|---|---|
| Complete rules | allow { ... } | allow if { ... } |
| Partial set rules | deny[msg] { ... } | deny contains msg if { ... } |
| Default assignment | default allow = false | default allow := false |
every keyword | Requires import future.keywords.every | Available without import |
in keyword | Requires import future.keywords.in | Available without import |
contains keyword | Requires import future.keywords.contains |
| Available without import |
if keyword | Requires import future.keywords.if | Available without import |
| Duplicate imports | Allowed | Error |
input and data import | Allowed | Error (import input / import data prohibited) |
# Check for v0 patterns across all Rego files
opa check --strict ./policies/
# List files that need migration
opa fmt --rego-v1 -l ./policies/
# Migrate and write in-place (RECOMMENDED FIRST STEP)
opa fmt --rego-v1 -w ./policies/
# Preview changes without writing
opa fmt --rego-v1 ./policies/policy.rego
opa fmt --rego-v1 handles most transformations automatically:
if to complete rulesdeny[msg] to deny contains msg ifdefault x = val to default x := valfuture.keywords importsimport rego.v1After opa fmt --rego-v1, manually address:
allow (bare rule) needs explicit assignmentif--v0-compatible flags# Strict check (catches remaining v0 patterns)
opa check --strict ./policies/
# Run all tests
opa test ./policies/ -v
# Lint with Regal
regal lint ./policies/
# v0
allow {
input.user.role == "admin"
}
# v1
allow if {
input.user.role == "admin"
}
# v0
deny[msg] {
some c in input.spec.containers
c.securityContext.privileged
msg := sprintf("privileged: %s", [c.name])
}
# v1
deny contains msg if {
some c in input.spec.containers
c.securityContext.privileged
msg := sprintf("privileged: %s", [c.name])
}
# v0
labels[key] = value {
some key, value in input.metadata.labels
}
# v1
labels[key] := value if {
some key, value in input.metadata.labels
}
# v0
default allow = false
# v1
default allow := false
# v0
import future.keywords.if
import future.keywords.in
import future.keywords.contains
import future.keywords.every
# v1 (remove all future.keywords imports - keywords are built-in)
# Also remove: import rego.v1
# v0
authorize = "allow" {
input.role == "admin"
} else = "deny" {
true
}
# v1
authorize := "allow" if {
input.role == "admin"
} else := "deny"
For gradual migration, OPA supports running v0 policies with compatibility flags:
# Run v0 policies on OPA 1.0+
opa eval --v0-compatible -d policy.rego -i input.json "data.authz.allow"
# Test v0 policies
opa test --v0-compatible ./policies/
# Check syntax in v0 mode
opa check --v0-compatible ./policies/
Environment variable: OPA_V0_COMPATIBLE=true
Add import rego.v1 to individual files to opt-in to v1 semantics in a v0 codebase:
package authz
import rego.v1 # This file uses v1 syntax
allow if {
input.user.role == "admin"
}
Gatekeeper ConstraintTemplates embed Rego in YAML. Migration requires updating the embedded Rego:
apiVersion: templates.gatekeeper.sh/v1