openflagr/flagr: a self-hosted feature flag and A/B testing microservice in Go
Flagr is a feature flagging, A/B testing and dynamic configuration microservice
At a glance
- What is it?
- Flagr is a Go service that answers POST /api/v1/evaluation with a variant and an optional JSON attachment. It suits teams that want flag evaluation as an HTTP call against their own database rather than a hosted SaaS.
- Who is it for?
- Adopt Flagr if you want flag evaluation to be a plain HTTP call against a database you operate, and you accept that the calling application does the caching. Do not adopt it if you need an SDK that evaluates flags locally with no network hop, or if you expect the README to answer operational questions such as rollback: it does not.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Flagr solves: flag decisions as a service call
Most feature flag systems ship a client library that evaluates rules inside your process. Flagr inverts that. The application makes an HTTP request to the Flagr service, and the service decides. The README states the contract directly: your app calls POST /api/v1/evaluation with who is asking (entityID, entityContext), and Flagr returns a variant and optional JSON attachment.
The audience is teams that already run their own infrastructure and want flag state to live in a database they control. The README lists SQLite, MySQL, PostgreSQL, or JSON/GitOps as self-hosting options, which means the flag definitions are not locked inside a vendor. A second audience is experimentation: the README describes running experiments with sticky assignment, so users stay in the same variant across calls.
That design has a cost that the README does not discuss. Every flag check is a network round trip unless the caller caches. Flagr is a microservice, and the README frames it that way, so the latency budget belongs to whoever integrates it. The published vegeta benchmark in the repository reports roughly 2k req/s with a sub-millisecond median, but that measures the service in isolation, not your application's end-to-end path.
How evaluation works: entityID, entityContext and the variant response
The mechanism is a single POST endpoint. The caller sends an entity identifier, an entity type, a context object, and the flag ID. Flagr evaluates the flag's targeting rules against that context and returns the selected variant. The README's own example uses entityID 127, entityType user, entityContext {"state": "NY"}, and flagID 1.
The entityContext is the interesting part. It is free-form JSON that the service evaluates against, which is why the README can advertise both A/B testing and dynamic configuration from the same endpoint. A config flag and an experiment flag differ in how you write the rules, not in the transport.
The response carries a variant and an optional JSON attachment. The attachment is how you return more than a label: a payload of settings, a string, whatever the flag needs to convey. The README does not document the full response schema in the excerpt, so the API reference at openflagr.github.io/flagr/api_docs is the place to confirm field names before you write a client.
There is also an enableDebug field in the example request. The README shows it set to true but does not explain what it returns, so treat it as a debugging aid to verify against the API docs rather than a documented contract.
Running Flagr with Docker and making a first evaluation call
The README's quick start is two commands. The image is published at ghcr.io/openflagr/flagr, and the container listens on port 18000, which the Dockerfile confirms via ENV PORT=18000 and EXPOSE 18000.
docker pull ghcr.io/openflagr/flagr
docker run -it -p 18000:18000 ghcr.io/openflagr/flagrAfter the container starts, open http://localhost:18000 in a browser. That serves the Vue 3 UI, which is where you create flags and targeting rules. The Dockerfile copies the built UI into ./browser/flagr-ui/dist inside the image, so the UI is present without a separate deployment.
Once a flag exists, evaluation is a plain HTTP call. The README publishes a hosted demo at try-flagr.onrender.com and gives this curl example against it:
curl -sS -X POST https://try-flagr.onrender.com/api/v1/evaluation \
-H 'content-type: application/json' \
-d '{
"entityID": "127",
"entityType": "user",
"entityContext": { "state": "NY" },
"flagID": 1,
"enableDebug": true
}'You should get a JSON body back. The README says it contains a variant and an optional attachment. The demo instance may cold-start, so a first request can be slow; the same request against your own container on localhost:18000 avoids that. If you prefer a typed client, the README lists official clients for Go, JavaScript, Python and Ruby, named goflagr, jsflagr, pyflagr and rbflagr.
The Docker image defaults to SQLite, and other constraints the README leaves open
The Dockerfile sets FLAGR_DB_DBDRIVER=sqlite3 and FLAGR_DB_DBCONNECTIONSTR=/data/demo_sqlite3.db, and copies buildscripts/demo_sqlite3.db into /data. That means the container you start with the quick start command is a demo, not a production deployment. The README lists MySQL, PostgreSQL and JSON/GitOps as alternatives, but the excerpt does not show the environment variables for them, so you have to read the self-hosting documentation to switch.
The same Dockerfile sets FLAGR_RECORDER_ENABLED=false. The repository contains docker-compose.kafka.yml and the go.mod lists Shopify/sarama, a Kafka client, plus a Kinesis producer. So there is an event-recording path, and the default image turns it off. If you want evaluation events, you are configuring something the README's quick start deliberately disables.
The bigger limitation is architectural. Because evaluation is a remote call, Flagr is the wrong tool if your application cannot tolerate a network dependency in the flag-check path, or if you need flags evaluated offline. An embedded library that reads a local rules file is a better fit there. Flagr is also the wrong tool if you want a managed service with no operational work: you own the database, the backups and the upgrades.
Flagr compared with Flagsmith and other hosted flag platforms
The related searches for this project include Flagsmith, which is a fair comparison because both present themselves as feature flag platforms. The difference is where evaluation happens. Flagr's README describes a service you call: POST /api/v1/evaluation returns a variant. Flagsmith's publicly documented model centers on an SDK that fetches flag state and evaluates it in the client, which removes the per-check network hop that Flagr's design implies.
That single difference drives most of the choice. If you want the smallest possible change to an application and no per-request latency added, an SDK-based platform wins. If you want the decision to be made centrally, in a service you host, against a context object you send per call, Flagr's model is the more direct fit.
A second contrast is storage. Flagr's README lists SQLite, MySQL, PostgreSQL, or JSON/GitOps, which means a GitOps workflow where flag definitions are files is a first-class option. That matters for teams that already review configuration changes through pull requests.
This article has not evaluated Flagsmith's feature set beyond that architectural difference, and no claim here should be read as a comparison of their capabilities.
Maintenance, licence and the cost of upgrading
The repository is not archived, and the last push was on 2026-09-23. The release history shows 1.2.4 on 2026-08-20, 1.2.3 on 2026-07-29 and 1.2.2 on 2026-07-03, so releases have been arriving on a roughly monthly cadence through that period. The README also notes that openflagr/flagr continues development from the original checkr/flagr, which is worth knowing if you find older documentation referring to the checkr organisation.
The licence is Apache-2.0, stated in the README and present as a LICENSE file at the repository root. Apache-2.0 is a permissive licence with an explicit patent grant. It does not impose copyleft obligations on your application. That is a description of the licence text, not legal advice; if your organisation has a policy on open source licences, run it past whoever owns that policy.
Upgrade cost is mostly the database. Because flag definitions live in your SQLite, MySQL or PostgreSQL instance, the upgrade procedure is a binary swap plus whatever schema migration the release requires. The README excerpt does not document a migration or rollback procedure, and the CHANGELOG.md file exists but is not reproduced here, so read the changelog for the version you are moving to before you deploy. If you run the JSON/GitOps backend instead, your definitions are files and the migration question is smaller.
Editorial conclusion
Adopt Flagr if you want flag evaluation to be a plain HTTP call against a database you operate, and you accept that the calling application does the caching. Do not adopt it if you need an SDK that evaluates flags locally with no network hop, or if you expect the README to answer operational questions such as rollback: it does not. Before committing, check that your entityContext shape matches the targeting rules you intend to write, and confirm which storage backend you will run in production, because the Docker image defaults to sqlite3 at /data/demo_sqlite3.db.
Frequently asked questions
What is openflagr/flagr?
It is an open-source Go service for feature flags, A/B tests and dynamic configuration, according to the README. Applications call POST /api/v1/evaluation with an entityID and entityContext, and Flagr returns a variant and an optional JSON attachment.
How do I run Flagr locally?
The README's quick start pulls ghcr.io/openflagr/flagr and runs it with port 18000 mapped to 18000, then you open http://localhost:18000. The Dockerfile sets the database driver to sqlite3 and the connection string to /data/demo_sqlite3.db, so the container starts as a demo instance.
Does Flagr have official clients for other languages?
The README lists four: goflagr for Go, jsflagr for JavaScript, pyflagr for Python and rbflagr for Ruby. Each is a separate repository under the openflagr organisation.
Which databases can Flagr use?
The README lists SQLite, MySQL, PostgreSQL, or JSON/GitOps for self-hosting. The published Docker image defaults to sqlite3, so switching backends means changing the database environment variables rather than editing code.
Should feature flags be removed?
The README does not address flag lifecycle or cleanup. It describes creating flags and evaluating them, and the repository does not document a retirement policy for flags that are fully rolled out.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/openflagr-flagr)