Composing OPA Solutions

Building awesome apps with OPA just got easier.

2 min readSep 29, 2021


OPA and the OPA logo design are registered trademarks of the Cloud Native Computing Foundation.

At Aserto, we use OPA heavily in our authorization API as the underlying decision engine. We’ve been looking for a simple way to compose our solution over the OPA engine, and the OPA SDK provided us with a good starting point.

We had some additional requirements, though: we wanted to

  • progressively unlock the engine’s capabilities
  • make these capabilities discoverable
  • extend the engine without sacrificing the ability to update the underlying OPA version

Bottom line, we needed a higher-level abstraction that would let us perform common tasks: build, test, run OPA policies, combined with the ability to configure them for a wide variety of use-cases in a discoverable, typed fashion.

We decided to use the options pattern as it provides a good balance between readability, discoverability of options, and the ability to grow your implementation as required.

This post will show how you can leverage the resulting “helper” package to build your OPA-based solutions, which we call runtime.


go get -u


Creating a new runtime is straightforward. OPA has many configuration options that can tweak the behavior of your application, so it’s best to read up on that. All these configuration options are available in the runtime.Config struct. As you’ll see later, this runtime can do many things — build policy bundles, run plugins and execute queries.

Simple Build

Let’s start with the simplest example — building a policy bundle.

Error handling is omitted for brevity.

You need to provide a context, and a logger instance (we’re opinionated here — we like zerolog a lot). Next, you call NewRuntime and get back your runtime instance, a cleanup function, and an error. Easy peasy. You can use the runtime instance to call Build and you’re done!

Run with a built-in

Ok, so that was super simple — what if I want to use the OPA engine to interpret queries and return the decisions?

Error handling is omitted for brevity.

The code looks very similar. You first create your runtime instance. In this example, we’re executing a query that references a custom function (or built-in).

Once the runtime struct is created, we start the plugin manager and wait for initialization to finish, so our bundles are loaded by OPA, and the runtime is ready to execute a query.

And that’s it! You’ve built a tiny app that can load rego bundles and answer queries.


At Aserto we use the “runtime” all the time. OPA is an amazing project, and we believe there’s value in making it accessible to developers that also want to build cool things on top.

You can start small and simple, and grow your implementation as needed.

Cheers from Aserto!




Welcome to modern authorization.

Recommended from Medium


See more recommendations