Flip features, not deploys.

Beacon is a feature flag platform written in Go. Write targeting rules as plain expressions, change them whenever you like, and every connected service picks up the change over Server-Sent Events. No redeploy, no restart.
production
3 connected

New checkout flow

new-checkout · boolean

Rule

Rider.city == "BANGALORE" and Rider.age > 20

v14 · enabled Live on 3 services
beacon server
  • checkout-apinew-checkout · v14on
  • rider-appnew-checkout · v14on
  • pricing-servicenew-checkout · v14on
Flip the switch or change the rule to push an update. Every service applies it without restarting.

Version 14 of new-checkout is enabled on all 3 services.

to check a flag whose rule is a single comparison
~400 ns
network calls when a service checks a flag
0
rule engine, shared by the server and the SDK
1
flag types: boolean, string, number and JSON
4

Measured on an Intel Core i5-13400F with Go 1.27. Full benchmark report

How it works

Change it once. Every service hears about it.

The Beacon server stores your flags and broadcasts each change. Services keep a copy in memory and evaluate rules themselves, so checking a flag never waits on the network.
  1. 01

    Define flags and rules

    Create a flag in an environment and write the rule that turns it on, such as enabling the new checkout only for riders in Bangalore.

  2. 02

    Beacon broadcasts the change

    Every create and update is pushed over a Server-Sent Events stream to each connected service. No polling, no redeploy, no restart.

  3. 03

    Services evaluate locally

    The SDK keeps the latest flags and compiled rules in memory. Checking a flag is a function call, and a service keeps its last known flags if the connection drops.

Rule language

Targeting rules you can read out loud.

A rule is a boolean expression over the data your service passes in. If you can say who a feature is for, you can write the rule.
  • Compare

    ==><>=<=

    Numbers and strings, reached with dotted paths like Rider.address.city.

  • Match lists

    in one ofin all of

    Check a value against a list, or require an array of tags to contain every one.

  • Combine

    andornot(…)( )

    Group conditions with parentheses. Evaluation stops as soon as the answer is known.

  • Fail loudly

    Syntax errors, missing fields and type mismatches come back as errors you can handle.

Evaluate against
{
  "Rider": {
    "city": "BANGALORE",
    "age": 34,
    "tags": ["vip"]
  }
}
  • Rider.city == "BANGALORE" and Rider.age > 20true
  • Rider.city in one of ["BANGALORE", "DELHI"]true
  • Rider.tags in all of ["vip", "new"]false
  • (Rider.age < 25 or Rider.age > 60) and not(Rider.city == "MUMBAI")false
  • Rider.plan == "pro"unknown identifier

The server and the SDK share one engine, so a rule gives the same answer wherever it runs. A missing field is an error, never a silent false.

Features

Everything around the flag, built in.

Environments, rollouts, schedules, history and access control are part of Beacon's data model from the start, so every flag gets them.
  • Projects and environments

    Group flags by project and give each environment its own state and rule. Flag and environment keys never change after creation, so code that references them keeps working.

  • Four flag types

    Serve more than on and off: a string variant, a numeric limit or a whole JSON config.

  • Percentage and gradual rollouts

    Release to a share of traffic, or ramp up step by step, on top of your targeting rule.

  • Scheduled windows

    Give a flag a start and an end time, and it switches on and off by itself.

  • Version history

    Every rule change saves a snapshot of the flag, so you can see who changed what, and when.

  • Roles and permissions

    Give each person a role on a project and, where needed, a different one per environment. Deny a single permission and it beats every grant.

  • Scoped API keys

    Services authenticate with per-project keys that carry only the permissions they need. Keys are stored hashed and can expire.

  • Google and GitHub sign-in

    Teammates sign in with an account they already have.

  • Email invitations

    Invite people to a project with a role. Invitations expire on their own.

  • Stale flag detection

    SDKs report when each flag was last evaluated, so dead flags stand out.

  • Keeps working offline

    A service that loses its connection keeps serving its last known flags.

Roadmap

Building in the open.

The rule engine and the HTTP server work today, so you can try the rule language right now. Flag management, the live update stream and the SDK are next.
  1. Rule language, compiler and evaluatorDone
  2. HTTP server with POST /evaluateDone
  3. Flag and rule management APIPlanned
  4. SSE update streamPlanned
  5. Service SDKPlanned
$ cd control-plane-server && go run ./cmd

$ curl -X POST localhost:8080/evaluate \
  -H 'Content-Type: application/json' \
  -d '{
    "rule": "Rider.city == \"Bangalore\" and Rider.age > 20",
    "data": {"Rider": {"city": "Bangalore", "age": 40}}
  }'

{"data": {"result": true}, "error": null}

Start the server, then send the request from a second terminal.

Ship the code once. Decide who sees it later.

Clone the repository, start the server and evaluate your first rule in a couple of minutes.