Skip to main content

Decision Search Language

Styra utilizes a dialect of the Lucene query language for the decision search. It is very similar to the search language found in Gmail, GitHub, Elasticsearch, Azure Search, and many others.

You can search a term using the following ways:


A query is divided into terms and operators. There are two types of terms, as follows:

  • Single term: A single term is a single word such as test or hello.
  • Phrase: A phrase is a group of words surrounded by double quotes such as "access denied".

Boolean Operators

Multiple terms can be combined using logical operators: AND (&&), OR (||), as well as NOT (!). By default, terms are combined using AND, so two single terms such as access denied are equivalent to access AND denied, which searches for decisions containing both words. access OR denied, on the other hand, searches for decisions containing "access", "denied", or both. Finally, NOT denied searches for decisions that don't contain "denied".


NOT (!) takes precedence over AND (&&), which takes precedence over OR (||). Precedence can be controlled by grouping terms: (abc OR def) hij. Without parentheses abc OR def hij is interpreted as abc OR (def AND hij).


Decisions consist of fields of different types. The following types are supported by the search language:

  • boolean: Unquoted terms true and false are considered to be Booleans.
  • integer: Unquoted terms that consist of digits only with an optional + or - prefix are interpreted as integers.
  • float: Unquoted terms containing two sequences of digits separated by a decimal point, such as 12.34 are interpreted as floating-point literals.

When Integers and Floats are present in the same expression, the expression type is assumed to be float.

  • date: Date literals. For more information, see the Dates section on this page.
  • string: Quoted strings, unquoted terms that do not fall into one of the types above, regular expression (/a.*b/), wildcard expressions (abc*), and fuzzy literals (abc~2) are all interpreted as strings.

Expression type is determined from the operand types. String serves as a fallback type when the type cannot be inferred. For example: in abc 123 query.


By default, the search is performed in all decision fields that corresponds to the expression type. However, it is possible to explicitly specify the field with key:query syntax. When applied to a group (example:key:(abc OR def)), the key serves as the default for inner expressions that don't have an explicit field (key:) prefix.

The following fields are accessible:

  • Each user-defined column identifies a searchable field with a corresponding key and type.

  • In addition, the following fields are built in:

    • agent_id (string): Unique OPA instance ID.
    • allowed (boolean): true if the decision was to authorize the request.
    • bundles (object): Lists all bundles used in the decision and the bundle revision digest for each.
    • decision_id (string): Unique decision ID.
    • error (string): Text representation of the evaluation error object.
    • input (string): Text representation of the OPA request input object.
    • path (string): Policy path.
    • query (string): Ad hoc query used for the OPA request.
    • reason (string): Statement explaining why the decision was made.
    • received (date): Styra-side timestamp when the decision batch was received.
    • requested_by (string): IP address and port of the service that requested a policy evaluation.
    • result (string): Text representation of the decision result object.
    • revision (string): Bundle revision digest when a single bundle is used.
    • system_id (string): Unique system ID.
    • stacks (string): IDs of stacks that contributed to the decision.
    • timestamp (date): OPA-side timestamp.
    • type (string): One of allowed, denied, advice, error.
  • A label_NAME (string) field is created for each label in the labels object of a decision. Characters in the label name that are not alpha-numeric are converted to underscores (_). For example, policy-type becomes label_policy_type.

If there is a naming conflict between a user-defined field and a built-in field, then the user-defined field will be used.

Key-query pairs can be delimited with = instead of : (e.g., key=query) in order to force the query to match strings exactly.


There is no difference between = and : if the field is not a string type.


Wildcard characters can be used to replace a single character (?) or zero or more characters (*) in a word.

For example:

qu?ck bro*

* returns all decisions that don't have numeric_column value. It can be used as a placeholder for any value for non-string types, as follows:

NOT numeric_column:*

Regular Expressions

Regular expression patterns can be embedded in the query string by wrapping them in forward-slashes (/):


For more information about Regular expression support, see the Regular expression syntax.

Fuzzy and Proximity Searches

The fuzzy character (~) can be used to match terms that are similar to, but not exactly the same as, the corresponding literal words.

For example:


This finds all terms which are at most one change away from the term (k ↔︎ c in this case). The distance can be specified explicitly.

For example: The following can handle two errors (l instead of i and k ↔︎ c).


It is also possible to search for multiple words within a specific distance from each other. To do a proximity search use the tilde (~) symbol at the end of a phrase. For example, "access denied"~3 finds instances where "access" and "denied" are within three words of each other.


Ranges can be specified for date, numeric, or string fields. Inclusive ranges are specified with square brackets [min TO max] and exclusive ranges with curly brackets {min TO max}:

  • Numbers 1..5: count:[1 TO 5].
  • Tags from alpha to omega, excluding omega but not alpha: tag:[alpha TO omega}.
  • Numbers from 10 upwards: count:[10 TO *].

Ranges with one side unbounded can also be specified with the following syntax:



Dates can be specified in any of the formats, as follows:

  • ISO format: "2019-07-24T06:13:04.827Z", "2019-02-22T21:11:04-07:00".
  • ISO without timezone: "2019-07-24T06:13:04".
  • date only: "2019-07-24".
  • date with timezone: "2019-07-24-07:00".
  • All of above with space separators: "2019-07-24 06:13:04.827 -07:00", "2019-07-24 -07:00", and so on.

When no time zone is specified in the date literal, the browser local time is used as a default.

Timestamps with less than millisecond precision are expanded into ranges:

"2019-07-24" ⟶ ["2019-07-24T00:00:00" TO "2019-07-25T00:00:00"}
"2019-07-24 12:34:56" ⟶ ["2019-07-24T12:34:56" TO "2019-07-25T12:34:57"}
"2019-07-24 12:34:56.7" ︎⟶ ["2019-07-24T12:34:56.7" TO "2019-07-25T12:34:56.8"}

Accordingly, timestamp:"2019-07-24" matches all decisions made on July 24, 2019.