Skip to main content


Regal is a linter for Rego, with the goal of making your Rego magnificent!


adj : of notable excellence or magnificence : splendid

- Merriam Webster

illustration of a viking representing the Regal logo


  • Identify common mistakes, bugs and inefficiencies in Rego policies, and suggest better approaches
  • Provide advice on best practices, coding style, and tooling
  • Allow users, teams and organizations to enforce custom rules on their policy code

Regal rules are to as large extent as possible written in Rego themselves, using the JSON representation of the Rego abstract syntax tree (AST) as input, a few additional custom built-in functions and some indexed data structures to help with linting.

Getting Started

Download Regal

MacOS and Linux

brew install styrainc/packages/regal
Manual download options

MacOS (Apple Silicon)

curl -L -o regal ""

MacOS (x86_64)

curl -L -o regal ""

Linux (x86_64)

curl -L -o regal ""
chmod +x regal


curl.exe -L -o regal.exe ""


docker pull

See all versions, and checksum files, at the Regal releases page, and published Docker images at the packages page.

Try it out!

First, author some Rego!


package authz

import future.keywords

default allow = false

deny if {
"admin" != input.user.roles[_]

allow if not deny

Next, run regal lint pointed at one or more files or directories to have them linted.

regal lint policy/
Rule:           not-equals-in-loop
Description: Use of != in loop
Category: bugs
Location: policy/authz.rego:8:10
Text: "admin" != input.user.roles[_]

Rule: implicit-future-keywords
Description: Use explicit future keyword imports
Category: imports
Location: policy/authz.rego:3:8
Text: import future.keywords

Rule: use-assignment-operator
Description: Prefer := over = for assignment
Category: style
Location: policy/authz.rego:5:1
Text: default allow = false

1 file linted. 3 violations found.

Note If you're running Regal on an existing policy library, you may want to disable the style category initially, as it will likely generate a lot of violations. You can do this by passing the --disable-category style flag to regal lint.


Regal comes with a set of built-in rules, grouped by category.

  • bugs: Common mistakes, potential bugs and inefficiencies in Rego policies.
  • custom: Custom, rules where enforcement can be adjusted to match your preferences.
  • idiomatic: Suggestions for more idiomatic constructs.
  • imports: Best practices for imports.
  • style: Rego Style Guide rules.
  • testing: Rules for testing and development.

The following rules are currently available:

bugsconstant-conditionConstant condition
bugsinvalid-metadata-attributeInvalid attribute in metadata annotation
bugsnot-equals-in-loopUse of != in loop
bugsrule-named-ifRule named "if"
bugsrule-shadows-builtinRule name shadows built-in
bugstop-level-iterationIteration in top-level assignment
bugsunused-return-valueNon-boolean return value unused
customforbidden-function-callForbidden function call
customnaming-conventionNaming convention violation
idiomaticcustom-has-key-constructCustom function may be replaced by in and object.keys
idiomaticcustom-in-constructCustom function may be replaced by in keyword
idiomaticnon-raw-regex-patternUse raw strings for regex patterns
idiomaticuse-in-operatorUse in to check for membership
idiomaticuse-some-for-output-varsUse some to declare output variables
importsavoid-importing-inputAvoid importing input
importsimplicit-future-keywordsUse explicit future keyword imports
importsimport-shadows-importImport shadows another import
importsredundant-aliasRedundant alias
importsredundant-data-importRedundant import of data
styleavoid-get-and-list-prefixAvoid get and list prefix for rules and functions
stylechained-rule-bodyAvoid chaining rule bodies
styledetached-metadataDetached metadata annotation
styleexternal-referenceReference to input, data or rule ref in function body
stylefile-lengthMax file length exceeded
stylefunction-arg-returnFunction argument used for return value
styleline-lengthLine too long
styleno-whitespace-commentComment should start with whitespace
styleopa-fmtFile should be formatted with opa fmt
styleprefer-snake-casePrefer snake_case for names
styleprefer-some-in-iterationPrefer some .. in for iteration
styletodo-commentAvoid TODO comments
styleunconditional-assignmentUnconditional assignment in rule body
styleuse-assignment-operatorPrefer := over = for assignment
testingdubious-print-sprintfDubious use of print and sprintf
testingfile-missing-test-suffixFiles containing tests should have a _test.rego suffix
testingidentically-named-testsMultiple tests with same name
testingmetasyntactic-variableMetasyntactic variable name
testingprint-or-trace-callCall to print or trace function
testingtest-outside-test-packageTest outside of test package
testingtodo-testTODO test encountered

By default, all rules except for those in the custom category are currently enabled.

If you'd like to see more rules, please open an issue for your feature request, or better yet, submit a PR! See the custom rules page for more information on how to develop your own rules, for yourself or for inclusion in Regal.

Custom Rules

The custom category is a special one, as the rules in this category allow you to enforce rules that are specific to your project, team or organization. This typically includes things like naming conventions, where you might want to ensure that, for example, all package names adhere to an organizational standard, like having a prefix matching the organization name.

Since these rules require configuration provided by the user, they are disabled by default. In order to enable them, see the configuration options available for each rule for how to configure them according to your requirements.

For more advanced requirements, see the guide on writing custom rules in Rego.


A custom configuration file may be used to override the default configuration options provided by Regal. The most common use case for this is to change the severity level of a rule. These three levels are available:

  • ignore — disable the rule entirely
  • warning — report the violation without changing the exit code of the lint command
  • error — report the violation and have the lint command exit with a non-zero exit code (default)

Additionally, some rules may have configuration options of their own. See the documentation page for a rule to learn more about it.


# Files can be excluded from all lint
# rules according to glob-patterns
- file1.rego
- "*_tmp.rego"
# don't report on todo comments
level: ignore
# custom rule configuration
max-line-length: 100
# warn on too long lines, but don't fail
level: warning
# not needed as error is the default, but
# being explicit won't hurt
level: error
# Files can be ignored.
# In this example, test files are ignored
- "*_test.rego"
# custom rule configuration
level: error
# ensure all package names start with "acmecorp" or "system"
- pattern: '^acmecorp\.[a-z_\.]+$|^system\.[a-z_\.]+$'
- package

Regal will automatically search for a configuration file (.regal/config.yaml) in the current directory, and if not found, traverse the parent directories either until either one is found, or the top of the directory hierarchy is reached. If no configuration file is found, Regal will use the default configuration.

A custom configuration may be also be provided using the --config-file/-c option for regal lint, which when provided will be used to override the default configuration.

CLI flags

For development, rules may also quickly be enabled or disabled using the relevant CLI flags for the regal lint command.

  • --disable-all disables all rules
  • --disable-category disables all rules in a category, overriding --enable-all (may be repeated)
  • --disable disables a specific rule, overriding --enable-all and --enable-category (may be repeated)
  • --enable-all enables all rules
  • --enable-category enables all rules in a category, overriding --disable-all (may be repeated)
  • --enable enables a specific rule, overriding --disable-all and --disable-category (may be repeated)
  • --ignore-files ignores files using glob patterns, overriding ignore in the config file (may be repeated)

All CLI flags override configuration provided in file.

Exit Codes

Exit codes are used to indicate the result of the lint command. The --fail-level provided for regal lint may be used to change the exit code behavior, and allows a value of either warning or error (default).

If --fail-level error is supplied, exit code will be zero even if warnings are present:

  • 0: no errors were found
  • 0: one or more warnings were found
  • 3: one or more errors were found

This is the default behavior.

If --fail-level warning is supplied, warnings will result in a non-zero exit code:

  • 0: no errors or warnings were found
  • 2: one or more warnings were found
  • 3: one or more errors were found

Inline Ignore Directives

If you'd like to ignore a specific violation, you can add an ignore directive above the line in question:

package policy

# regal ignore:prefer-snake-case
camelCase := "yes"

The format of an ignore directive is regal ignore:<rule-name>,<rule-name>..., where <rule-name> is the name of the rule to ignore. Multiple rules may be added to the same ignore directive, separated by commas.

Note that at this point in time, Regal only considers the line following the ignore directive, i.e. it does not ignore entire blocks of code (like rules, functions or even packages). See configuration if you want to ignore certain rules altogether.

Output Formats

The regal lint command allows specifying the output format by using the --format flag. The available output formats are:

  • pretty (default) - Human-readable table-like output where each violation is printed with a detailed explanation
  • compact - Human-readable output where each violation is printed on a single line
  • json - JSON output, suitable for programmatic consumption
  • github - GitHub workflow command output, ideal for use in GitHub Actions. Annotates PRs and creates a job summary from the linter report



Regal the Rego Linter, CNCF London meetup, June 2023 Regal the Rego Linter



Regal is currently in beta. End-users should not expect any drastic changes, but any API may change without notice. If you want to embed Regal in another project or product, please reach out!


The roadmap for Regal currently looks like this:

  • 50 rules!
  • Add custom (or organizational, opinionated, or...) category for built-in "custom", or organizational rules, to enforce things like naming conventions. The most common customizations should not require writing custom rules, but be made available in configuration.
  • Simplify custom rules authoring by providing command for scaffolding
  • Make more rules consider nested AST nodes
  • GitHub Action

The roadmap is updated when all the current items have been completed.


For questions, discussions and announcements related to Styra products, services and open source projects, please join the Styra community on Slack!