---
title: Policy Language
kind: documentation
weight: 2
toc: true
---

```live:eg:module:hidden
package example
import future.keywords
```

OPA is purpose built for reasoning about information represented in structured
documents. The data that your service and its users publish can be inspected and
transformed using OPA’s native query language Rego.

## What is Rego?

Rego was inspired by [Datalog](https://en.wikipedia.org/wiki/Datalog), which is
a well understood, decades old query language. Rego extends Datalog to support
structured document models such as JSON.

Rego queries are assertions on data stored in OPA. These queries can be used to
define policies that enumerate instances of data that violate the expected state
of the system.

{{< info >}}
The examples in this section try to represent the best practices. As such, they
make use of keywords that are meant to become standard keywords at some point in
time, but have been introduced gradually. These _future keywords_ can be enabled
using

```live:eg/import:module:read_only
import future.keywords
```
{{< /info >}}

## Why use Rego?

Use Rego for defining policy that is easy to read and write.

Rego focuses on providing powerful support for referencing nested documents and
ensuring that queries are correct and unambiguous.

Rego is declarative so policy authors can focus on what queries should return
rather than how queries should be executed. These queries are simpler and more
concise than the equivalent in an imperative language.

Like other applications which support declarative query languages, OPA is able
to optimize queries to improve performance.

## The Basics

This section introduces the main aspects of Rego.

The simplest rule is a single expression and is defined in terms of a [Scalar Value](#scalar-values):

```live:eg/pi:module
pi := 3.14159
```

Rules define the content of documents. We can query for the content of the `pi` document generated by the rule above:

```live:eg/pi:query:read_only,merge_down
pi
```
```live:eg/pi:output
```

Rules can also be defined in terms of [Composite Values](#composite-values):

```live:eg/rect:module
rect := {"width": 2, "height": 4}
```

The result:

```live:eg/rect:query:read_only,merge_down
rect
```
```live:eg/rect:output
```

You can compare two scalar or composite values, and when you do so you are checking if the two values are the same JSON value.

```live:eg/rect/compare:query:merge_down
rect == {"height": 4, "width": 2}
```
```live:eg/rect/compare:output
```

You can define a new concept using a rule. For example, `v` below is true if the equality expression is true.

```live:eg/undefined:module
v if "hello" == "world"
```

If we evaluate `v`, the result is `undefined` because the body of the rule never
evaluates to `true`. As a result, the document generated by the rule is not
defined.

```live:eg/undefined:query:hidden
v
```
```live:eg/undefined:output:expect_undefined
```

Expressions that refer to undefined values are also undefined. This includes comparisons such as `!=`.

```live:eg/undefined/expression:query:merge_down
v == true
```
```live:eg/undefined/expression:output:expect_undefined,merge_down
```
```live:eg/undefined/other_expression:query:merge_down
v != true
```
```live:eg/undefined/other_expression:output:expect_undefined
```

We can define rules in terms of [Variables](#variables) as well:

```live:eg/rules:module
t if { x := 42; y := 41; x > y }
```

The formal syntax uses the semicolon character `;` to separate expressions. Rule
bodies can separate expressions with newlines and omit the semicolon:

```live:eg/rules/newlines:module:read_only
t2 if {
    x := 42
    y := 41
    x > y
}
```

Note that the future keyword `if` is optional. We could have written `v` and `t2` like this:

```live:eg/rules/newlines_no_if:module:read_only
v { "hello" == "world" }

t2 {
    x := 42
    y := 41
    x > y
}
```

When evaluating rule bodies, OPA searches for variable bindings that make all of
the expressions true. There may be multiple sets of bindings that make the rule
body true. The rule body can be understood intuitively as:

```
expression-1 AND expression-2 AND ... AND expression-N
```

The rule itself can be understood intuitively as:

```
rule-name IS value IF body
```

If the **value** is omitted, it defaults to **true**.

When we query for the value of `t` we see the obvious result:

```live:eg/rules:query:hidden
t
```
```live:eg/rules:output
```

Rego [References](#references) help you refer to nested documents. For example, with:

```live:eg/references:module
sites := [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}]
```
And
```live:eg/references/basic:module
r if {
    some site in sites
    site.name == "prod"
}
```

The rule `r` above asserts that there exists (at least) one document within `sites` where the `name` attribute equals `"prod"`.

The result:

```live:eg/references/basic:query:hidden
r
```
```live:eg/references/basic:output
```

We can generalize the example above with a rule that defines a set document instead of a boolean document:

```live:eg/references/helper:module
q contains name if {
    some site in sites
    name := site.name
}
```

The value of `q` is a set of names

```live:eg/references/helper:query:hidden
q
```
```live:eg/references/helper:output
```

We can re-write the rule `r` from above to make use of `q`. We will call the new rule `p`:

```live:eg/references/helper/composed:module
p if q["prod"]
```

Querying `p` will have the same result:

```live:eg/references/helper/composed:query:hidden
p
```
```live:eg/references/helper/composed:output
```

As you can see, rules which have arguments can be queried with input values:

```live:eg/references/helper/argument:query:merge_down
q["smoke2"]
```
```live:eg/references/helper/argument:output:expect_undefined
```

If you made it this far, congratulations!

This section introduced the main aspects of Rego. The rest of this document
walks through each part of the language in more detail.

For a concise reference, see the [Policy
Reference](../policy-reference) document.


## Scalar Values

Scalar values are the simplest type of term in Rego. Scalar values can be [Strings](#strings), numbers, booleans, or null.

Documents can be defined solely in terms of scalar values. This is useful for defining constants that are referenced in multiple places. For example:

```live:eg/scalars:module
greeting   := "Hello"
max_height := 42
pi         := 3.14159
allowed    := true
location   := null
```

These documents can be queried like any other:

```live:eg/scalars:query:merge_down
[greeting, max_height, pi, allowed, location]
```
```live:eg/scalars/str:output
```

## Strings

Rego supports two different types of syntax for declaring strings. The first is likely to be the most familiar: characters surrounded by double quotes.
In such strings, certain characters must be escaped to appear in the string, such as double quotes themselves, backslashes, etc. See the [Policy
Reference](../policy-reference/#grammar) for a formal definition.

The other type of string declaration is a raw string declaration. These are made of characters surrounded by backticks (`` ` ``), with the exception
that raw strings may not contain backticks themselves. Raw strings are what they sound like: escape sequences are not interpreted, but instead taken
as the literal text inside the backticks. For example, the raw string `` `hello\there` `` will be the text "hello\there", not "hello" and "here"
separated by a tab.  Raw strings are particularly useful when constructing regular expressions for matching, as it eliminates the need to double
escape special characters.

A simple example is a regex to match a valid Rego variable. With a regular string, the regex is `"[a-zA-Z_]\\w*"`, but with raw strings, it becomes `` `[a-zA-Z_]\w*` ``.

## Composite Values

Composite values define collections. In simple cases, composite values can be treated as constants like [Scalar Values](#scalar-values):

```live:eg/cube:module
cube := {"width": 3, "height": 4, "depth": 5}
```

The result:

```live:eg/cube:query:merge_down
cube.width
```
```live:eg/cube:output
```

Composite values can also be defined in terms of [Variables](#variables) or [References](#references). For example:

```live:eg/composite_variables:query:merge_down
a := 42
b := false
c := null
d := {"a": a, "x": [b, c]}
```
```live:eg/composite_variables:output
```

By defining composite values in terms of variables and references, rules can define abstractions over raw data and other rules.

### Objects

Objects are unordered key-value collections. In Rego, any value type can be
used as an object key. For example, the following assignment maps port **numbers**
to a list of IP addresses (represented as strings).

```live:eg/objects:module:merge_down
ips_by_port := {
    80: ["1.1.1.1", "1.1.1.2"],
    443: ["2.2.2.1"],
}
```
```live:eg/objects/lookup:query:merge_down
ips_by_port[80]
```
```live:eg/objects/lookup:output:merge_down
```
```live:eg/objects/iteration:query:merge_down
some port; ips_by_port[port][_] == "2.2.2.1"
```
```live:eg/objects/iteration:output
```

When Rego values are converted to JSON non-string object keys are marshalled
as strings (because JSON does not support non-string object keys).

```live:eg/objects/marshal:query:merge_down
ips_by_port
```
```live:eg/objects/marshal:output
```

### Sets

In addition to arrays and objects, Rego supports set values. Sets are unordered
collections of unique values. Just like other composite values, sets can be
defined in terms of scalars, variables, references, and other composite values.
For example:

```live:eg/cube/sets:query:merge_down
s := {cube.width, cube.height, cube.depth}
```
```live:eg/cube/sets:output
```

> Set documents are collections of values without keys. OPA represents set
documents as arrays when serializing to JSON or other formats that do not
support a set data type. The important distinction between sets and arrays or
objects is that sets are unkeyed while arrays and objects are keyed, i.e., you
cannot refer to the index of an element within a set.

When comparing sets, the order of elements does not matter:

```live:eg/set_equality:query:merge_down
{1,2,3} == {3,1,2}
```
```live:eg/set_equality:output
```

Because sets are unordered, variables inside sets must be unified with a ground
value outside of the set. If the variable is not unified with a ground value
outside the set, OPA will complain:

```live:eg/set_unification:query:merge_down
{1,2,3} == {3,x,2}
```
```live:eg/set_unification:output:expect_unsafe_var
```

Because sets share curly-brace syntax with objects, and an empty object is
defined with `{}`, an empty set has to be constructed with a different syntax:

```live:eg/set_construction:query:merge_down
count(set())
```
```live:eg/set_construction:output
```

## Variables

Variables are another kind of term in Rego. They appear in both the head and body of rules.

Variables appearing in the head of a rule can be thought of as input and output of the rule. Unlike many programming languages, where a variable is either an input or an output, in Rego a variable is simultaneously an input and an output. If a query supplies a value for a variable, that variable is an input, and if the query does not supply a value for a variable, that variable is an output.

For example:

```live:eg/variables:module
sites := [
    {"name": "prod"},
    {"name": "smoke1"},
    {"name": "dev"}
]

q contains name if {
    some site in sites
    name := site.name
}
```

In this case, we evaluate `q` with a variable `x` (which is not bound to a value). As a result, the query returns all of the values for `x` and all of the values for `q[x]`, which are always the same because `q` is a set.

```live:eg/variables:query:merge_down
q[x]
```
```live:eg/variables:output
```

On the other hand, if we evaluate `q` with an input value for `name` we can determine whether `name` exists in the document defined by `q`:

```live:eg/variables/value:query:merge_down
q["dev"]
```
```live:eg/variables/value:output
```

Variables appearing in the head of a rule must also appear in a non-negated equality expression within the same rule. This property ensures that if the rule is evaluated and all of the expressions evaluate to true for some set of variable bindings, the variable in the head of the rule will be defined.

## References

References are used to access nested documents.

The examples in this section use the data defined in the [Examples](#example-data) section.

The simplest reference contains no variables. For example, the following reference returns the hostname of the second server in the first site document from our example data:

```live:eg/data/ref1:query:merge_down
sites[0].servers[1].hostname
```
```live:eg/data/ref1:output
```

References are typically written using the “dot-access” style. The canonical form does away with `.` and closely resembles dictionary lookup in a language such as Python:

```live:eg/data/ref2:query:merge_down
sites[0]["servers"][1]["hostname"]
```
```live:eg/data/ref2:output
```

Both forms are valid, however, the dot-access style is typically more readable. Note that there are four cases where brackets must be used:

  1. String keys containing characters other than `[a-z]`, `[A-Z]`, `[0-9]`, or `_` (underscore).
  2. Non-string keys such as numbers, booleans, and null.
  3. Variable keys which are described later.
  4. Composite keys which are described later.

The prefix of a reference identifies the root document for that reference. In
the example above this is `sites`. The root document may be:

  * a local variable inside a rule.
  * a rule inside the same package.
  * a document stored in OPA.
  * a documented temporarily provided to OPA as part of a transaction.
  * an array, object or set, e.g. `[1, 2, 3][0]`.
  * a function call, e.g. `split("a.b.c", ".")[1]`.
  * a [comprehension](#comprehensions).

### Variable Keys

References can include variables as keys. References written this way are used to select a value from every element in a collection.

The following reference will select the hostnames of all the servers in our
example data:

```live:eg/data/var_key:query:merge_down
sites[i].servers[j].hostname
```
```live:eg/data/var_key:output
```

Conceptually, this is the same as the following imperative (Python) code:

```python
def hostnames(sites):
    result = []
    for site in sites:
        for server in site.servers:
            result.append(server.hostname)
    return result
```

In the reference above, we effectively used variables named `i` and `j` to iterate the collections. If the variables are unused outside the reference, we prefer to replace them with an underscore (`_`) character. The reference above can be rewritten as:

```live:eg/data/meh_key:query:merge_down
sites[_].servers[_].hostname
```
```live:eg/data/meh_key:output
```

The underscore is special because it cannot be referred to by other parts of the rule, e.g., the other side of the expression, another expression, etc. The underscore can be thought of as a special iterator. Each time an underscore is specified, a new iterator is instantiated.

> Under the hood, OPA translates the `_` character to a unique variable name that does not conflict with variables and rules that are in scope.

### Composite Keys

References can include [Composite Values](#composite-values) as keys if the key is being used to refer into a set. Composite keys may not be used in refs
for base data documents, they are only valid for references into virtual documents.

This is useful for checking for the presence of composite values within a set, or extracting all values within a set matching some pattern.
For example:

```live:eg/composite_key:module
s := {[1, 2], [1, 4], [2, 6]}
```

```live:eg/composite_key/1:query:merge_down
s[[1, 2]]
```
```live:eg/composite_key/1:output
```

```live:eg/composite_key/2:query:merge_down
s[[1, x]]
```
```live:eg/composite_key/2:output
```

### Multiple Expressions

Rules are often written in terms of multiple expressions that contain references to documents. In the following example, the rule defines a set of arrays where each array contains an application name and a hostname of a server where the application is deployed.

```live:eg/data/multi:module
apps_and_hostnames[[name, hostname]] {
    some i, j, k
    name := apps[i].name
    server := apps[i].servers[_]
    sites[j].servers[k].name == server
    hostname := sites[j].servers[k].hostname
}
```

The result:

```live:eg/data/multi:query:merge_down
apps_and_hostnames[x]
```
```live:eg/data/multi:output
```

Don’t worry about understanding everything in this example right now. There are just two important points:

  1. Several variables appear more than once in the body. When a variable is used in multiple locations, OPA will only produce documents for the rule with the variable bound to the same value in all expressions.
  2. The rule is joining the `apps` and `sites` documents implicitly. In Rego (and other languages based on Datalog), joins are implicit.

### Self-Joins

Using a different key on the same array or object provides the equivalent of self-join in SQL. For example, the following rule defines a document containing apps deployed on the same site as `"mysql"`:

```live:eg/data/self_join:module
same_site[apps[k].name] {
    some i, j, k
    apps[i].name == "mysql"
    server := apps[i].servers[_]
    server == sites[j].servers[_].name
    other_server := sites[j].servers[_].name
    server != other_server
    other_server == apps[k].servers[_]
}
```

The result:

```live:eg/data/self_join:query:merge_down
same_site[x]
```
```live:eg/data/self_join:output
```


## Comprehensions

Comprehensions provide a concise way of building [Composite Values](#composite-values) from sub-queries.

Like [Rules](#rules), comprehensions consist of a head and a body. The body of a comprehension can be understood in exactly the same way as the body of a rule, that is, one or more expressions that must all be true in order for the overall body to be true. When the body evaluates to true, the head of the comprehension is evaluated to produce an element in the result.

The body of a comprehension is able to refer to variables defined in the outer body. For example:

```live:eg/data/comprehension_intro:query:merge_down
region := "west"
names := [name | sites[i].region == region; name := sites[i].name]
```
```live:eg/data/comprehension_intro:output
```

In the above query, the second expression contains an [Array Comprehension](#array-comprehensions) that refers to the `region` variable. The region variable will be bound in the outer body.

> When a comprehension refers to a variable in an outer body, OPA will reorder expressions in the outer body so that variables referred to in the comprehension are bound by the time the comprehension is evaluated.

Comprehensions are similar to the same constructs found in other languages like Python. For example, we could write the above comprehension in Python as follows:

```python
# Python equivalent of Rego comprehension shown above.
names = [site.name for site in sites if site.region == "west"]
```

Comprehensions are often used to group elements by some key. A common use case for comprehensions is to assist in computing aggregate values (e.g., the number of containers running on a host).

### Array Comprehensions

Array Comprehensions build array values out of sub-queries. Array Comprehensions have the form:

```
[ <term> | <body> ]
```

For example, the following rule defines an object where the keys are application names and the values are hostnames of servers where the application is deployed. The hostnames of servers are represented as an array.

```live:eg/data/array_comprehension:module
app_to_hostnames[app_name] := hostnames if {
    app := apps[_]
    app_name := app.name
    hostnames := [hostname | name := app.servers[_]
                            s := sites[_].servers[_]
                            s.name == name
                            hostname := s.hostname]
}
```

The result:

```live:eg/data/array_comprehension:query:read_only,merge_down
app_to_hostnames[app]
```
```live:eg/data/array_comprehension:output
```

### Object Comprehensions

Object Comprehensions build object values out of sub-queries. Object Comprehensions have the form:

```
{ <key>: <term> | <body> }
```

We can use Object Comprehensions to write the rule from above as a comprehension instead:

```live:eg/data/object_comprehension:module
app_to_hostnames := {app.name: hostnames |
    app := apps[_]
    hostnames := [hostname |
                    name := app.servers[_]
                    s := sites[_].servers[_]
                    s.name == name
                    hostname := s.hostname]
}
```

The result is the same:

```live:eg/data/object_comprehension:query:read_only,merge_down
app_to_hostnames[app]
```
```live:eg/data/object_comprehension:output
```

Object comprehensions are not allowed to have conflicting entries, similar to rules:

```live:eg/data/object_comprehension_conflicting:query:merge_down
{"foo": y | z := [1, 2, 3]; y := z[_] }
```
```live:eg/data/object_comprehension_conflicting:output:expect_conflict
```

### Set Comprehensions

Set Comprehensions build set values out of sub-queries. Set Comprehensions have the form:

```
{ <term> | <body> }
```

For example, to construct a set from an array:
```live:eg/data/set_comprehension:module:merge_down
a := [1, 2, 3, 4, 3, 4, 3, 4, 5]
b := {x | x = a[_]}
```
```live:eg/data/set_comprehension:query:hidden
a
b
```
```live:eg/data/set_comprehension:output
```


## Rules

Rules define the content of [Virtual Documents](../philosophy#how-does-opa-work) in
OPA. When OPA evaluates a rule, we say OPA *generates* the content of the
document that is defined by the rule.

The sample code in this section make use of the data defined in [Examples](#example-data).

### Generating Sets

The following rule defines a set containing the hostnames of all servers:

```live:eg/data/rules:module:read_only
hostnames contains name if {
    name := sites[_].servers[_].hostname
}
```
Note that the (future) keyword `if` is optional here.

When we query for the content of `hostnames` we see the same data as we would if we queried using the `sites[_].servers[_].hostname` reference directly:

```live:eg/data/rules:query:read_only,merge_down
hostnames[name]
```
```live:eg/data/rules:output
```

This example introduces a few important aspects of Rego.

First, the rule defines a set document where the contents are defined by the variable `name`. We know this rule defines a set document because the head only includes a key. All rules have the following form (where key, value, and body are all optional):

```
<name> <key>? <value>? <body>?
```

For a more formal definition of the rule syntax, see the [Policy Reference](../policy-reference/#grammar) document.

Second, the `sites[_].servers[_].hostname` fragment selects the `hostname` attribute from all of the objects in the `servers` collection. From reading the fragment in isolation we cannot tell whether the fragment refers to arrays or objects. We only know that it refers to a collections of values.

Third, the `name := sites[_].servers[_].hostname` expression binds the value of the `hostname` attribute to the variable `name`, which is also declared in the head of the rule.

### Generating Objects

Rules that define objects are very similar to rules that define sets.

```live:eg/data/rule_objects:module
apps_by_hostname[hostname] := app if {
    some i
    server := sites[_].servers[_]
    hostname := server.hostname
    apps[i].servers[_] == server.name
    app := apps[i].name
}
```

The rule above defines an object that maps hostnames to app names. The main difference between this rule and one which defines a set is the rule head: in addition to declaring a key, the rule head also declares a value for the document.

The result:

```live:eg/data/rule_objects:query:merge_down
apps_by_hostname["helium"]
```
```live:eg/data/rule_objects:output
```

### Incremental Definitions

A rule may be defined multiple times with the same name. When a rule is defined
this way, we refer to the rule definition as *incremental* because each
definition is additive. The document produced by incrementally defined rules is
the union of the documents produced by each individual rule.

For example, we can write a rule that abstracts over our `servers` and
`containers` data as `instances`:

```live:eg/data/incremental_rule:module
instances contains instance if {
    server := sites[_].servers[_]
    instance := {"address": server.hostname, "name": server.name}
}

instances contains instance if {
    container := containers[_]
    instance := {"address": container.ipaddress, "name": container.name}
}
```

If the head of the rule is same, we can chain multiple rule bodies together to
obtain the same result.  We don't recommend using this form anymore.

```live:eg/data/incremental_rule_nr:module:read_only
instances contains instance if {
    server := sites[_].servers[_]
    instance := {"address": server.hostname, "name": server.name}
} {
    container := containers[_]
    instance := {"address": container.ipaddress, "name": container.name}
}
```

An incrementally defined rule can be intuitively understood as `<rule-1> OR <rule-2> OR ... OR <rule-N>`.

The result:

```live:eg/data/incremental_rule:query:read_only,merge_down
instances[x]
```
```live:eg/data/incremental_rule:output
```

### Complete Definitions

In addition to rules that *partially* define sets and objects, Rego also
supports so-called *complete* definitions of any type of document. Rules provide
a complete definition by omitting the key in the head. Complete definitions are
commonly used for constants:

```live:complete:module:read_only
pi := 3.14159
```

> Rego allows authors to omit the body of rules. If the body is omitted, it
> defaults to true.

Documents produced by rules with complete definitions can only have one value at
a time. If evaluation produces multiple values for the same document, an error
will be returned.

For example:

```live:eg/conflicting_rules:module
# Define user "bob" for test input.
user := "bob"

# Define two sets of users: power users and restricted users. Accidentally
# include "bob" in both.
power_users := {"alice", "bob", "fred"}
restricted_users := {"bob", "kim"}

# Power users get 32GB memory.
max_memory := 32 if power_users[user]

# Restricted users get 4GB memory.
max_memory := 4 if restricted_users[user]
```

Error:

```live:eg/conflicting_rules:output:expect_conflict
```

OPA returns an error in this case because the rule definitions are in *conflict*. The value produced by max_memory cannot be 32 and 4 **at the same time**.

The documents produced by rules with complete definitions may still be undefined:

```live:eg/conflicting_rules/undefined:query:merge_down
max_memory with user as "johnson"
```
```live:eg/conflicting_rules/undefined:output:expect_undefined
```

In some cases, having an undefined result for a document is not desirable. In those cases, policies can use the [Default Keyword](#default-keyword) to provide a fallback value.

### Functions

Rego supports user-defined functions that can be called with the same semantics as [Built-in Functions](#built-in-functions). They have access to both the [the data Document](../philosophy/#the-opa-document-model) and [the input Document](../philosophy/#the-opa-document-model).

For example, the following function will return the result of trimming the spaces from a string and then splitting it by periods.

```live:eg/basic_function:module:merge_down
trim_and_split(s) := x if {
     t := trim(s, " ")
     x := split(t, ".")
}
```
```live:eg/basic_function:query:merge_down
trim_and_split("   foo.bar ")
```
```live:eg/basic_function:output
```

Functions may have an arbitrary number of inputs, but exactly one output. Function arguments may be any kind of term. For example, suppose we have the following function:

```live:eg/function_input:module:read_only
foo([x, {"bar": y}]) := z if {
    z := {x: y}
}
```

The following calls would produce the logical mappings given:

| Call                                                    | ``x``      | ``y``                         |
| ------------------------------------------------------- | ---------- | ----------------------------- |
| ``z := foo(a) ``                                        | ``a[0]``   | ``a[1].bar``                  |
| ``z := foo(["5", {"bar": "hello"}])``                   | ``"5"``    | ``"hello"``                   |
| ``z := foo(["5", {"bar": [1, 2, 3, ["foo", "bar"]]}])`` | ``"5"``    | ``[1, 2, 3, ["foo", "bar"]]`` |


If you need multiple outputs, write your functions so that the output is an array, object or set
containing your results. If the output term is omitted, it is equivalent to having the output term
be the literal `true`. Furthermore, `if` can be used to write shorter definitions. That is, the
function declarations below are equivalent:

```live:eg/function_output_unset:module:read_only
f(x) { x == "foo" }
f(x) if { x == "foo" }
f(x) if x == "foo"

f(x) := true { x == "foo" }
f(x) := true if { x == "foo" }
f(x) := true if x == "foo"
```

The outputs of user functions have some additional limitations, namely that they must resolve to a single value. If you write a function that has multiple possible bindings for an output variable, you will get a conflict error:

```live:eg/function_single_output:module:merge_down
p(x) := y if {
    y := x[_]
}
```
```live:eg/function_single_output:query:merge_down
p([1, 2, 3])
```
```live:eg/function_single_output:output:expect_conflict
```

It is possible in Rego to define a function more than once, to achieve a conditional selection of which function to execute:

Functions can be defined incrementally.

```live:eg/double_function_define:module
q(1, x) := y if {
    y := x
}
q(2, x) := y if {
    y := x*4
}
```

```live:eg/double_function_define/1:query:merge_down
q(1, 2)
```
```live:eg/double_function_define/1:output
```

```live:eg/double_function_define/2:query:merge_down
q(2, 2)
```
```live:eg/double_function_define/2:output
```

A given function call will execute all functions that match the signature given. If a call matches multiple functions, they must produce the same output, or else a conflict error will occur:

```live:eg/double_function_define_diff_out:module
r(1, x) := y if {
    y := x
}

r(x, 2) := y if {
    y := x*4
}
```

```live:eg/double_function_define_diff_out:query:merge_down
r(1, 2)
```
```live:eg/double_function_define_diff_out:output:expect_conflict
```

On the other hand, if a call matches no functions, then the result is undefined.
```live:eg/double_function_define_undefined:module
s(x, 2) := y if {
    y := x * 4
}
```

```live:eg/double_function_define_undefined/1:query:merge_down
s(5, 2)
```
```live:eg/double_function_define_undefined/1:output
```

```live:eg/double_function_define_undefined/2:query:merge_down
s(5, 3)
```
```live:eg/double_function_define_undefined/2:output:expect_undefined
```

## Negation

To generate the content of a [Virtual Document](../philosophy#how-does-opa-work), OPA attempts to bind variables in the body of the rule such that all expressions in the rule evaluate to True.

This generates the correct result when the expressions represent assertions about what states should exist in the data stored in OPA. In some cases, you want to express that certain states *should not* exist in the data stored in OPA. In these cases, negation must be used.

For safety, a variable appearing in a negated expression must also appear in another non-negated equality expression in the rule.

> OPA will reorder expressions to ensure that negated expressions are evaluated after other non-negated expressions with the same variables. OPA will reject rules containing negated expressions that do not meet the safety criteria described above.

The simplest use of negation involves only scalar values or variables and is equivalent to complementing the operator:

```live:eg/simple_negation:module
t if {
    greeting := "hello"
    not greeting == "goodbye"
}
```

The result:

```live:eg/simple_negation:query:read_only,merge_down
t
```
```live:eg/simple_negation:output
```

Negation is required to check whether some value *does not* exist in a collection. That is, complementing the operator in an expression such as `p[_] == "foo"` yields `p[_] != "foo"`. However, this is not equivalent to `not p["foo"]`.

For example, we can write a rule that defines a document containing names of apps not deployed on the `"prod"` site:

```live:eg/data/negation:module
prod_servers contains name if {
    some site in sites
    site.name == "prod"
    some server in site.servers
    name := server.name
}

apps_in_prod contains name if {
    some site in sites
    some app in apps
    name := app.name
    some server in app.servers
    prod_servers[server]
}

apps_not_in_prod contains name if {
    some app in apps
    name := app.name
    not apps_in_prod[name]
}
```

The result:

```live:eg/data/negation:query:read_only,merge_down
apps_not_in_prod[name]
```
```live:eg/data/negation:output
```

## Universal Quantification (FOR ALL)

Rego allows for several ways to express universal quantification.

For example, imagine you want to express a policy that says (in English):

```
There must be no apps named "bitcoin-miner".
```

The most expressive way to state this in Rego is using the `every` keyword:

```live:eg/data/every_alternative:module:read_only
import future.keywords.every

no_bitcoin_miners_using_every if {
    every app in apps {
        app.name != "bitcoin-miner"
    }
}
```

Variables in Rego are _existentially quantified_ by default: when you write

```live:eg/data/every_alternative/1:query:merge_down
array := ["one", "two", "three"]; array[i] == "three"
```

The query will be satisfied **if there is an `i`** such that the query's
expressions are simultaneously satisfied.
```live:eg/data/every_alternative/1:output
```

Therefore, there are other ways to express the desired policy.

For this policy, you can also define a rule that finds if there exists a bitcoin-mining
app (which is easy using the `some` keyword). And then you use negation to check
that there is NO bitcoin-mining app. Technically, you're using 2 negations and
an existential quantifier, which is logically the same as a universal
quantifier.

For example:

```live:eg/data/correct_negation:module
no_bitcoin_miners_using_negation if not any_bitcoin_miners

any_bitcoin_miners if {
    some app in apps
    app.name == "bitcoin-miner"
}
```

```live:eg/data/correct_negation/1:query:merge_down
no_bitcoin_miners_using_negation with apps as [{"name": "web"}]
```
```live:eg/data/correct_negation/1:output
```

```live:eg/data/correct_negation/2:query:merge_down
no_bitcoin_miners_using_negation with apps as [{"name": "bitcoin-miner"}, {"name": "web"}]
```
```live:eg/data/correct_negation/2:output:expect_undefined
```

{{< info >}}
The `undefined` result above is expected because we did not define a default
value for `no_bitcoin_miners_using_negation`. Since the body of the rule fails
to match, there is no value generated.
{{< /info >}}

A common mistake is to try encoding the policy with a rule named `no_bitcoin_miners`
like so:

```live:eg/data/incorrect_no_bitcoin:module:read_only
no_bitcoin_miners if {
    app := apps[_]
    app.name != "bitcoin-miner"  # THIS IS NOT CORRECT.
}
```

It becomes clear that this is incorrect when you use the [`some`](#some-keyword)
keyword, because the rule is true whenever there is SOME app that is not a
bitcoin-miner:

```live:eg/data/incorrect_no_bitcoin_some:module
no_bitcoin_miners if {
    some app in apps
    app.name != "bitcoin-miner"
}
```

You can confirm this by querying the rule:

```live:eg/data/incorrect_no_bitcoin_some:query:merge_down
no_bitcoin_miners with apps as [{"name": "bitcoin-miner"}, {"name": "web"}]
```
```live:eg/data/incorrect_no_bitcoin_some:output
```

The reason the rule is incorrect is that variables in Rego are _existentially
quantified_. This means that rule bodies and queries express FOR ANY and not FOR
ALL. To express FOR ALL in Rego complement the logic in the rule body (e.g.,
`!=` becomes `==`) and then complement the check using negation (e.g.,
`no_bitcoin_miners` becomes `not any_bitcoin_miners`).

Alternatively, we can implement the same kind of logic inside a single rule
using [Comprehensions](#comprehensions).

```live:eg/data/comprehesion_alternative:module:read_only
no_bitcoin_miners_using_comprehension if {
    bitcoin_miners := {app | some app in apps; app.name == "bitcoin-miner"}
    count(bitcoin_miners) == 0
}
```

{{< info >}}
Whether you use negation, comprehensions, or `every` to express FOR ALL is up to you.
The `every` keyword should lend itself nicely to a rule formulation that closely
follows how requirements are stated, and thus enhances your policy's readability.

The comprehension version is more concise than the negation variant, and does not
require a helper rule while the negation version is more verbose but a bit simpler
and allows for more complex ORs.
{{< /info >}}

## Modules

In Rego, policies are defined inside *modules*. Modules consist of:

  * Exactly one [Package](#packages) declaration.
  * Zero or more [Import](#imports) statements.
  * Zero or more [Rule](#rules) definitions.

Modules are typically represented in Unicode text and encoded in UTF-8.

### Comments

Comments begin with the `#` character and continue until the end of the line.

### Packages

Packages group the rules defined in one or more modules into a particular namespace. Because rules are namespaced they can be safely shared across projects.

Modules contributing to the same package do not have to be located in the same directory.

The rules defined in a module are automatically exported. That is, they can be queried under OPA’s [Data API](../rest-api#data-api) provided the appropriate package is given. For example, given the following module:

```live:package_declaration:module:read_only
package opa.examples

pi := 3.14159
```

The `pi` document can be queried via the Data API:

```http
GET https://example.com/v1/data/opa/examples/pi HTTP/1.1
```

Valid package names are variables or references that only contain string operands. For example, these are all valid package names:

```
package foo
package foo.bar
package foo.bar.baz
package foo["bar.baz"].qux
```

These are invalid package names:

```
package 1foo        # not a variable
package foo[1].bar  # contains non-string operand
```

For more details see the language [Grammar](../policy-reference/#grammar).

### Imports

Import statements declare dependencies that modules have on documents defined outside the package. By importing a document, the identifiers exported by that document can be referenced within the current module.

All modules contain implicit statements which import the `data` and `input` documents.

Modules use the same syntax to declare dependencies on [Base and Virtual Documents](../philosophy#how-does-opa-work).

```live:import_data:module:read_only
package opa.examples
import future.keywords # uses 'in' and 'contains' and 'if'

import data.servers

http_servers contains server if {
    some server in servers
    "http" in server.protocols
}
```

Similarly, modules can declare dependencies on query arguments by specifying an import path that starts with `input`.

```live:import_input:module:read_only
package opa.examples
import future.keywords

import input.user
import input.method

# allow alice to perform any operation.
allow if user == "alice"

# allow bob to perform read-only operations.
allow if {
    user == "bob"
    method == "GET"
}

# allows users assigned a "dev" role to perform read-only operations.
allow if {
    method == "GET"
    input.user in data.roles["dev"]
}

# allows user catherine access on Saturday and Sunday
allow if {
    user == "catherine"
    day := time.weekday(time.now_ns())
    day in ["Saturday", "Sunday"]
}
```

Imports can include an optional `as` keyword to handle namespacing issues:

```live:import_namespacing:module:read_only
package opa.examples
import future.keywords

import data.servers as my_servers

http_servers contains server if {
    some server in my_servers
    "http" in server.protocols
}
```

## Some Keyword

The `some` keyword allows queries to explicitly declare local variables. Use the
`some` keyword in rules that contain unification statements or references with
variable operands **if** variables contained in those statements are not
declared using `:=` .

| Statement | Example | Variables |
| --- | --- | --- |
| Unification | `input.a = [["b", x], [y, "c"]]` | `x` and `y` |
| Reference with variable operands | `data.foo[i].bar[j]` | `i` and `j` |

For example, the following rule generates tuples of array indices for servers in
the "west" region that contain "db" in their name. The first element in the
tuple is the site index and the second element is the server index.

```live:eg/data/some:module
tuples contains [i, j] if {
    some i, j
    sites[i].region == "west"
    server := sites[i].servers[j] # note: 'server' is local because it's declared with :=
    contains(server.name, "db")
}
```

If we query for the tuples we get two results:

```live:eg/data/some/i:query:hidden
tuples
```
```live:eg/data/some/i:output
```

Since we have declared `i`, `j`, and `server` to be local, we can introduce
rules in the same package without affecting the result above:

```live:eg/data/some/i:module
# Define a rule called 'i'
i := 1
```

If we had not declared `i` with the `some` keyword, introducing the `i` rule
above would have changed the result of `tuples` because the `i` symbol in the
body would capture the global value. Try removing `some i, j` and see what happens!

The `some` keyword is not required but it's recommended to avoid situations like
the one above where introduction of a rule inside a package could change
behaviour of other rules.

For using the `some` keyword with iteration, see
[the documentation of the `in` operator](#membership-and-iteration-in).

## Every Keyword

{{< info >}}
To ensure backwards-compatibility, new keywords (like `every`) are introduced slowly.
In the first stage, users can opt-in to using the new keywords via a special import:
`import future.keywords` introduces _all_ future keywords, and
`import future.keywords.every` introduces the `every` keyword described here.

There is no need to also import `future.keywords.in`, that is **implied** by importing
`future.keywords.every`.

At some point in the future, the keyword will become _standard_, and the import will
become a no-op that can safely be removed. This should give all users ample time to
update their policies, so that the new keyword will not cause clashes with existing
variable names.
{{< /info >}}

```live:eg/data/every0:module:merge_down
import future.keywords.every

names_with_dev if {
    some site in sites
    site.name == "dev"

    every server in site.servers {
        endswith(server.name, "-dev")
    }
}
```
```live:eg/data/every0:query:merge_down
names_with_dev
```
```live:eg/data/every0:output
```

The `every` keyword takes an (optional) key argument, a value argument, a domain, and a
block of further queries, its "body".

The keyword is used to explicity assert that its body is true for *any element in the domain*.
It will iterate over the domain, bind its variables, and check that the body holds
for those bindings.
If one of the bindings does not yield a successful evaluation of the body, the overall
statement is undefined.

If the domain is empty, the overall statement is true.

Evaluating `every` does **not** introduce new bindings into the rule evaluation.

Used with a key argument, the index, or property name (for objects), comes into the
scope of the body evaluation:

```live:eg/every1:module:merge_down
import future.keywords.every

array_domain if {
    every i, x in [1, 2, 3] { x-i == 1 } # array domain
}

object_domain if {
    every k, v in {"foo": "bar", "fox": "baz" } { # object domain
        startswith(k, "f")
        startswith(v, "b")
    }
}

set_domain if {
    every x in {1, 2, 3} { x != 4 } # set domain
}
```
```live:eg/every1:output
```

Semantically, `every x in xs { p(x) }` is equivalent to, but shorter than, a "not-some-not"
construct using a helper rule:

```live:eg/every2:module:merge_down
import future.keywords.every

xs := [2, 2, 4, 8]
larger_than_one(x) := x > 1

rule_every if {
    every x in xs { larger_than_one(x) }
}

not_less_or_equal_one if not lte_one

lte_one if {
    some x in xs
    not larger_than_one(x)
}
```
```live:eg/every2:output
```

Negating `every` is forbidden. If you desire to express `not every x in xs { p(x) }`
please use `some x in xs; not p(x)` instead.

## With Keyword

The `with` keyword allows queries to programmatically specify values nested
under the [input Document](../philosophy/#the-opa-document-model) or the
[data Document](../philosophy/#the-opa-document-model), or built-in functions.

For example, given the simple authorization policy in the [Imports](#imports)
section, we can write a query that checks whether a particular request would be
allowed:

```live:import_input/1:query:merge_down
allow with input as {"user": "alice", "method": "POST"}
```
```live:import_input/1:output
```

```live:import_input/2:query:merge_down
allow with input as {"user": "bob", "method": "GET"}
```
```live:import_input/2:output
```

```live:import_input/3:query:merge_down
not allow with input as {"user": "bob", "method": "DELETE"}
```
```live:import_input/3:output
```

```live:import_input/4:query:merge_down
allow with input as {"user": "charlie", "method": "GET"} with data.roles as {"dev": ["charlie"]}
```
```live:import_input/4:output
```

```live:import_input/5:query:merge_down
not allow with input as {"user": "charlie", "method": "GET"} with data.roles as {"dev": ["bob"]}
```
```live:import_input/5:output
```

```live:import_input/6:query:merge_down
allow with input as {"user": "catherine", "method": "GET"}
      with data.roles as {"dev": ["bob"]}
      with time.weekday as "Sunday"
```
```live:import_input/6:output
```

The `with` keyword acts as a modifier on expressions. A single expression is
allowed to have zero or more `with` modifiers. The `with` keyword has the
following syntax:

```
<expr> with <target-1> as <value-1> [with <target-2> as <value-2> [...]]
```

The `<target>`s must be references to values in the input document (or the input
document itself) or data document, or references to functions (built-in or not).

{{< info >}}
When applied to the `data` document, the `<target>` must not attempt to
partially define virtual documents. For example, given a virtual document at
path `data.foo.bar`, the compiler will generate an error if the policy
attempts to replace `data.foo.bar.baz`.
{{< /info >}}

The `with` keyword only affects the attached expression. Subsequent expressions
will see the unmodified value. The exception to this rule is when multiple
`with` keywords are in-scope like below:

```live:multiple_with:module:read_only
inner := [x, y] if {
    x := input.foo
    y := input.bar
}

middle := [a, b] if {
    a := inner with input.foo as 100
    b := input
}

outer := result if {
    result := middle with input as {"foo": 200, "bar": 300}
}
```

When `<target>` is a reference to a function, like `http.send`, then
its `<value>` can be any of the following:
1. a value: `with http.send as {"body": {"success": true }}`
2. a reference to another function: `with http.send as mock_http_send`
3. a reference to another (possibly custom) built-in function: `with custom_builtin as less_strict_custom_builtin`.

When the replacement value is a function, its arity needs to match the replaced
function's arity; and the types must be compatible.

Replacement functions can call the function they're replacing **without causing
recursion**.
See the following example:

```live:eg/with_builtins:module:read_only
f(x) := count(x)

mock_count(x) := 0 if "x" in x
mock_count(x) := count(x) if not "x" in x
```

```live:eg/with_builtins/1:query:merge_down
f([1, 2, 3]) with count as mock_count
```
```live:eg/with_builtins/1:output
```

```live:eg/with_builtins/2:query:merge_down
f(["x", "y", "z"]) with count as mock_count
```
```live:eg/with_builtins/2:output
```

Each replacement function evaluation will start a new scope: it's valid to use
`with <builtin1> as ...` in the body of the replacement function -- for example:

```live:eg/with_builtins_nested:module:read_only
f(x) := count(x) if {
    rule_using_concat with concat as "foo,bar"
}

mock_count(x) := 0 if "x" in x
mock_count(x) := count(x) if not "x" in x

rule_using_concat if {
    concat(",", input.x) == "foo,bar"
}
```
```live:eg/with_builtins_nested/1:query:merge_down
f(["x", "y", "z"]) with count as mock_count with input.x as ["baz"]
```
```live:eg/with_builtins_nested/1:output
```

Note that function replacement via `with` does not affect the evaluation of
the function arguments: if `input.x` is undefined, the replacement of `concat`
does not change the result of the evaluation:

```live:eg/with_builtins_nested/2:query:merge_down
count(input.x) with count as 3 with input.x as ["x"]
```
```live:eg/with_builtins_nested/2:output
```

```live:eg/with_builtins_nested/3:query:merge_down
count(input.x) with count as 3 with input as {}
```
```live:eg/with_builtins_nested/3:output:expect_undefined
```

## Default Keyword

The `default` keyword allows policies to define a default value for documents
produced by rules with [Complete Definitions](#complete-definitions). The
default value is used when all of the rules sharing the same name are undefined.

For example:

```live:eg/default:module
default allow := false

allow if {
    input.user == "bob"
    input.method == "GET"
}

allow if input.user == "alice"
```

When the `allow` document is queried, the return value will be either `true` or `false`.

```live:eg/default:query:hidden
allow
```
```live:eg/default:input:merge_down
{
    "user": "bob",
    "method": "POST"
}
```
```live:eg/default:output
```

Without the default definition, the `allow` document would simply be undefined for the same input.

When the `default` keyword is used, the rule syntax is restricted to:

```
default <name> := <term>
```

The term may be any scalar, composite, or comprehension value but it may not be
a variable or reference. If the value is a composite then it may not contain
variables or references.

## Else Keyword

The ``else``  keyword is a basic control flow construct that gives you control
over rule evaluation order.

Rules grouped together with the ``else`` keyword are evaluated until a match is
found. Once a match is found, rule evaluation does not proceed to rules further
in the chain.

The ``else`` keyword is useful if you are porting policies into Rego from an
order-sensitive system like IPTables.

```live:eg/else:module
authorize := "allow" if {
    input.user == "superuser"           # allow 'superuser' to perform any operation.
} else := "deny" {
    input.path[0] == "admin"            # disallow 'admin' operations...
    input.source_network == "external"  # from external networks.
} # ... more rules
```
```live:eg/else:query:hidden
authorize
```

In the example below, evaluation stops immediately after the first rule even
though the input matches the second rule as well.

```live:eg/else/1:input:merge_down
{
  "path": [
    "admin",
    "exec_shell"
  ],
  "source_network": "external",
  "user": "superuser"
}
```
```live:eg/else/1:output
```

In the next example, the input matches the second rule (but not the first) so
evaluation continues to the second rule before stopping.

```live:eg/else/2:input:merge_down
{
  "path": [
    "admin",
    "exec_shell"
  ],
  "source_network": "external",
  "user": "alice"
}
```
```live:eg/else/2:output
```

The `else` keyword may be used repeatedly on the same rule and there is no
limit imposed on the number of `else` clauses on a rule.

## Operators

### Membership and iteration: `in`

{{< info >}}
To ensure backwards-compatibility, new keywords (like `in`) are introduced slowly.
In the first stage, users can opt-in to using the new keywords via a special import:
`import future.keywords` introduces _all_ future keywords, and
`import future.keywords.in` introduces the `in` keyword described here.

At some point in the future, the keyword will become _standard_, and the import will
become a no-op that can safely be removed. This should give all users ample time to
update their policies, so that the new keyword will not cause clashes with existing
variable names.
{{< /info >}}

The membership operator `in` lets you check if an element is part of a collection (array, set, or object). It always evaluates to `true` or `false`:

```live:eg/member1:module:merge_down
import future.keywords.in

p := [x, y, z] if {
    x := 3 in [1, 2, 3]            # array
    y := 3 in {1, 2, 3}            # set
    z := 3 in {"foo": 1, "bar": 3} # object
}
```
```live:eg/member1:output
```

When providing two arguments on the left-hand side of the `in` operator,
and an object or an array on the right-hand side, the first argument is
taken to be the key (object) or index (array), respectively:

```live:eg/member1c:module:merge_down
import future.keywords.in

p := [x, y] if {
    x := "foo", "bar" in {"foo": "bar"}    # key, val with object
    y := 2, "baz" in ["foo", "bar", "baz"] # key, val with array
}
```
```live:eg/member1c:output
```

**Note** that in list contexts, like set or array definitions and function
arguments, parentheses are required to use the form with two left-hand side
arguments -- compare:

```live:eg/member1d:module:merge_down
import future.keywords.in

p := x if {
    x := { 0, 2 in [2] }
}
q := x if {
    x := { (0, 2 in [2]) }
}
w := x if {
    x := g((0, 2 in [2]))
}
z := x if {
    x := f(0, 2 in [2])
}

f(x, y) := sprintf("two function arguments: %v, %v", [x, y])
g(x) := sprintf("one function argument: %v", [x])
```
```live:eg/member1d:output
```

Combined with `not`, the operator can be handy when asserting that an element is _not_
member of an array:

```live:eg/member1a:module:merge_down
import future.keywords.in

deny if not "admin" in input.user.roles

test_deny {
    deny with input.user.roles as ["operator", "user"]
}
```
```live:eg/member1a:output
```

**Note** that expressions using the `in` operator _always return `true` or `false`_, even
when called in non-collection arguments:

```live:eg/member1b:module:merge_down
import future.keywords.in

q := x if {
    x := 3 in "three"
}
```
```live:eg/member1b:output
```

Using the `some` variant, it can be used to introduce new variables based on a collections' items:

```live:eg/member2:module:merge_down
import future.keywords.in

p[x] {
    some x in ["a", "r", "r", "a", "y"]
}

q[x] {
    some x in {"s", "e", "t"}
}

r[x] {
    some x in {"foo": "bar", "baz": "quz"}
}
```
```live:eg/member2:output
```

Furthermore, passing a second argument allows you to work with _object keys_ and _array indices_:
```live:eg/member3:module:merge_down
import future.keywords.in

p[x] {
    some x, "r" in ["a", "r", "r", "a", "y"] # key variable, value constant
}

q[x] = y if {
     some x, y in ["a", "r", "r", "a", "y"] # both variables
}

r[y] = x if {
    some x, y in {"foo": "bar", "baz": "quz"}
}
```
```live:eg/member3:output
```

Any argument to the `some` variant can be a composite, non-ground value:

```live:eg/member4:module:merge_down
import future.keywords.in

p[x] = y if {
    some x, {"foo": y} in [{"foo": 100}, {"bar": 200}]
}
p[x] = y if {
    some {"bar": x}, {"foo": y} in {{"bar": "b"}: {"foo": "f"}}
}
```
```live:eg/member4:output
```

### Equality: Assignment, Comparison, and Unification

Rego supports three kinds of equality: assignment (`:=`), comparison (`==`), and unification `=`. We recommend using assignment (`:=`) and comparison (`==`) whenever possible for policies that are easier to read and write.

#### Assignment `:=`

The assignment operator (`:=`) is used to assign values to variables. Variables assigned inside a rule are locally scoped to that rule and shadow global variables.

```live:eg/assignment1:module:read_only
x := 100

p if {
    x := 1     # declare local variable 'x' and assign value 1
    x != 100   # true because 'x' refers to local variable
}
```

Assigned variables are not allowed to appear before the assignment in the
query. For example, the following policy will not compile:

```live:eg/assignment2:module:merge_down
p if {
    x != 100
    x := 1     # error because x appears earlier in the query.
}

q if {
    x := 1
    x := 2     # error because x is assigned twice.
}
```
```live:eg/assignment2:output:expect_assigned_above,expect_referenced_above
```

A simple form of destructuring can be used to unpack values from arrays and assign them to variables:

```live:eg/assignment3:module:read_only
address := ["3 Abbey Road", "NW8 9AY", "London", "England"]

in_london if {
    [_, _, city, country] := address
    city == "London"
    country == "England"
}
```
```live:eg/assignment3:output
```


#### Comparison `==`

Comparison checks if two values are equal within a rule.  If the left or right hand side contains a variable that has not been assigned a value, the compiler throws an error.

```live:eg/comparison1:module:merge_down
p if {
    x := 100
    x == 100   # true because x refers to the local variable
}
```
```live:eg/comparison1:output
```

```live:eg/comparison2:module:merge_down
y := 100
q if {
    y == 100   # true because y refers to the global variable
}
```
```live:eg/comparison2:output
```

```live:eg/comparison3:module:merge_down
r if {
    z == 100   # compiler error because z has not been assigned a value
}
```
```live:eg/comparison3:output:expect_unsafe_var
```

#### Unification `=`

Unification (`=`) combines assignment and comparison. Rego will assign variables to values that make the comparison true. Unification lets you ask for values for variables that make an expression true.

```live:eg/unification1:query:merge_down
# Find values for x and y that make the equality true
[x, "world"] = ["hello", y]
```
```live:eg/unification1:output
```

```live:eg/data/unification2:query:merge_down
sites[i].servers[j].name = apps[k].servers[m]
```
```live:eg/data/unification2:output
```

As opposed to when assignment (`:=`) is used, the order of expressions in a rule does not affect the document’s content.

```live:eg/expression_order:module
s if {
    x > y
    y = 41
    x = 42
}
```

#### Best Practices for Equality

Here is a comparison of the three forms of equality.

```
Equality  Applicable    Compiler Errors            Use Case
--------  -----------   -------------------------  ----------------------
:=        Everywhere    Var already assigned       Assign variable
==        Everywhere    Var not assigned           Compare values
=         Everywhere    Values cannot be computed  Express query
```

Best practice is to use assignment `:=` and comparison `==` wherever possible. The additional compiler checks help avoid errors when writing policy, and the additional syntax helps make the intent clearer when reading policy.

Under the hood `:=` and `==` are syntactic sugar for `=`, local variable creation, and additional compiler checks.


### Comparison Operators

The following comparison operators are supported:

```live:comparison_operators:module:read_only
a  ==  b  #  `a` is equal to `b`.
a  !=  b  #  `a` is not equal to `b`.
a  <   b  #  `a` is less than `b`.
a  <=  b  #  `a` is less than or equal to `b`.
a  >   b  #  `a` is greater than `b`.
a  >=  b  #  `a` is greater than or equal to `b`.
```

None of these operators bind variables contained
in the expression. As a result, if either operand is a variable, the variable
must appear in another expression in the same rule that would cause the
variable to be bound, i.e., an equality expression or the target position of
a built-in function.


## Built-in Functions

In some cases, rules must perform simple arithmetic, aggregation, and so on.
Rego provides a number of built-in functions (or “built-ins”) for performing
these tasks.

Built-ins can be easily recognized by their syntax. All built-ins have the
following form:

```
<name>(<arg-1>, <arg-2>, ..., <arg-n>)
```

Built-ins usually take one or more input values and produce one output
value. Unless stated otherwise, all built-ins accept values or variables as
output arguments.

If a built-in function is invoked with a variable as input, the variable must
be _safe_, i.e., it must be assigned elsewhere in the query.

Built-ins can include "." characters in the name. This allows them to be
namespaced. If you are adding custom built-ins to OPA, consider namespacing
them to avoid naming conflicts, e.g., `org.example.special_func`.

See the [Policy Reference](../policy-reference#built-in-functions) document for
details on each built-in function.

### Errors

By default, built-in function calls that encounter runtime errors evaluate to
undefined (which can usually be treated as `false`) and do not halt policy
evaluation. This ensures that built-in functions can be called with invalid
inputs without causing the entire policy to stop evaluating.

In most cases, policies do not have to implement any kind of error handling
logic. If error handling is required, the built-in function call can be negated
to test for undefined. For example:

```live:eg/errors:module:merge_down
allow if {
    io.jwt.verify_hs256(input.token, "secret")
    [_, payload, _] := io.jwt.decode(input.token)
    payload.role == "admin"
}

reason contains "invalid JWT supplied as input" if {
    not io.jwt.decode(input.token)
}
```
```live:eg/errors:input:merge_down
{
    "token": "a poorly formatted token"
}
```
```live:eg/errors:output
```

If you wish to disable this behaviour and instead have built-in function call
errors treated as exceptions that halt policy evaluation enable "strict built-in
errors" in the caller:

API | Flag
--- | ---
`POST v1/data` (HTTP) | `strict-builtin-errors` query parameter
`GET v1/data` (HTTP) | `strict-builtin-errors` query parameter
`opa eval` (CLI) | `--strict-builtin-errors`
`opa run` (REPL) | `> strict-builtin-errors`
`rego` Go module | `rego.StrictBuiltinErrors(true)` option
Wasm | Not Available

## Example Data

The rules below define the content of documents describing a simplistic deployment environment. These documents are referenced in other sections above.

```live:eg/data:module
sites := [
    {
        "region": "east",
        "name": "prod",
        "servers": [
            {
                "name": "web-0",
                "hostname": "hydrogen"
            },
            {
                "name": "web-1",
                "hostname": "helium"
            },
            {
                "name": "db-0",
                "hostname": "lithium"
            }
        ]
    },
    {
        "region": "west",
        "name": "smoke",
        "servers": [
            {
                "name": "web-1000",
                "hostname": "beryllium"
            },
            {
                "name": "web-1001",
                "hostname": "boron"
            },
            {
                "name": "db-1000",
                "hostname": "carbon"
            }
        ]
    },
    {
        "region": "west",
        "name": "dev",
        "servers": [
            {
                "name": "web-dev",
                "hostname": "nitrogen"
            },
            {
                "name": "db-dev",
                "hostname": "oxygen"
            }
        ]
    }
]

apps := [
    {
        "name": "web",
        "servers": ["web-0", "web-1", "web-1000", "web-1001", "web-dev"]
    },
    {
        "name": "mysql",
        "servers": ["db-0", "db-1000"]
    },
    {
        "name": "mongodb",
        "servers": ["db-dev"]
    }
]

containers := [
    {
        "image": "redis",
        "ipaddress": "10.0.0.1",
        "name": "big_stallman"
    },
    {
        "image": "nginx",
        "ipaddress": "10.0.0.2",
        "name": "cranky_euclid"
    }
]
```
