Platform
One platform for flags,tests and safe releases.
Target users, test the rules, review the change, then deliver it as a signed bundle to every connected SDK in about 0.2 seconds. Every step leaves a record you can check.
- Rule 01Internal staffcontextin segmentinternal-staff serve true
- Rule 02EU rollout25% → 50%regionin[EU]ANDsignedIneqtrueRollout by key50%true inside · false otherwise
- Default
- falseenabled, no rule matched
- Off
- falseflag disabled
rules[1].serve.percentage
- 25
+ 50
Draft differs from r184. SDKs keep r184 until you publish.
Open change requestOrdered rules
The first rule that matches decides. Each result carries the rule and the reason.
Deterministic rollout
MurmurHash3 of the flag and the user key. Raising 25% to 50% keeps everyone already in.
Draft, then publish
Edits change the draft. Nothing reaches an SDK until a revision is published.
Flags
Typed values, not just on and off.
Boolean, string, number and JSON flags, each with a purpose and a lifetime. A flag's key and type never change, so the code that reads it never breaks.
- Four types: boolean, string, number and JSON, validated against the type (and an optional JSON schema) before they can be saved.
- A purpose for every flag (release, experiment, operational, permission) and permanent flags for kill switches.
- Client exposure per flag: browser keys receive only client-exposed flags.
- Flags are archived, not deleted. An archived flag returns your fallback.
Percentage rollouts are deterministic
Type any user key. The bucket is computed in your browser with the same MurmurHash3 code the edge, the SDK, the CLI and CI use, so it lands in the same column on every row.
hash("checkout-v2", "user_1") → 40.61 < 50 ✓ · rollout 50%
Targeting
Rules you can read. Results you can explain.
Rules are data, evaluated in order. Conditions compare context attributes or reuse segments, and every evaluation says which rule decided and why.
- 15 operators: equality, lists, strings, numbers, presence and segments.
- Segments are defined once per project and can reference each other up to four levels deep.
- No user code runs during evaluation, and evaluation never throws.
Try a context
checkout-v2 · r184Sample rules for checkout-v2
- 01 segment internal-staff → true
- 02 region in ["EU"] AND signedIn = true → 50% true
- default → false
Value
false
Reason
rule_match
Rule
02
Bucket
56.82
Evaluated by @nanoflags/engine in your browser · sample rules
Environments
Compare before you promote.
Each environment has its own draft, revisions and keys. Promotion copies selected flag configurations from one draft to another and keeps a record of what it copied.
- New projects start with Development, Staging and Production. Production starts protected.
- Promotion never publishes. The target's next publish is linked to the promotion record.
- If the target changed while you were reviewing, the promotion is refused instead of overwriting it.
- checkout-v2Staging · 50% · EU, signed inProduction · 25% · EU, signed in
- new-pricing-pageStaging · on · internal-staffProduction · off
- search-rankingStaging · "relevance-v2"Production · "relevance-v2"
- dark-modeStaging · onProduction · on
Promotion record
- source
- staging r212 · draft matched
- target
- production draft · base r184
- checksum
- a41e09 → 7c0b3d
- publish
- linked on the next publish
Scenario checks
Unit tests for flag changes.
A scenario is a saved context with the value you expect. Run scenarios on the draft before you publish, in the dashboard or in CI. Where they are required, a publish waits until every scenario in scope passes on that exact draft.
- Pass means deep-equal: no type coercion, no partial credit.
- Editing the draft makes earlier runs stop counting.
- The same engine runs in the dashboard, the CLI, the GitHub Action and the SDK.
Run them in CI
nanoflags scenarios run --source draftEU signed-in users get the new checkout
{ region: "EU", signedIn: true, key: "u_18" }
expected trueactual true
Signed-out visitors keep the old checkout
{ region: "EU", signedIn: false }
expected falseactual false
Internal staff always see it
{ staff: true, region: "US" }
expected trueactual true
US customers stay out of the rollout
{ region: "US", signedIn: true }
expected falseactual truematched Rule 02 (region in [EU, US])
Change requests
Someone else signs off. Never the author.
Group the flags you are changing in a change request with a reason. Where approval is required, publishing goes through a change with enough independent approvals, each bound to the exact draft it reviewed.
- The author, and anyone who edited the draft since the change started, can't approve it.
- Edit the draft after an approval and the approval goes stale.
- API keys can't bypass review: an admin key can't publish where approval is required.
- draft
- testing
- awaiting_approval
- approved
- published
author maya
draft 9f3c1a
reason Error rate flat for 48 h at 25%. Next step of the rollout plan.
Scenario checks
4 / 4 passed on draft 9f3c1a · CI key
Approvals · 1 required
- mayaauthor · cannot approve
- samedited this draft · cannot approve
- leeapproved 9f3c1a · 12:04 UTC
Delivery
Signed at the source. Pushed to every SDK.
A publish is signed with Ed25519 and pushed over WebSockets on Cloudflare's network. The SDK verifies it, swaps it in atomically and evaluates locally.
How we measure it222ms
p50, database commit → SDK listener
327ms
p95, same path
latency_summary · last 24 h · 1,418 samples
- Evaluation is local and synchronous: no network call per flag.
- If the connection drops, the SDK keeps evaluating the last configuration it verified.
- Browser keys receive only client-exposed flags and the segments they use.
SDKs and tools
Fits the workflow you already have.
Browser and Node.js today, React hooks, an OpenFeature provider for JS/TS, and tools for CI and pull requests. The code that runs in your app is Apache-2.0.
- @nanoflags/sdk
JavaScript & Node SDK
Local evaluation, signature verification, last-good config. No runtime dependencies.
Docs - @nanoflags/sdk/react
React
Provider and hooks on top of the SDK. Pass a bootstrap bundle so server and client render the same.
Docs - @nanoflags/openfeature-provider
OpenFeature provider
Call flags through the OpenFeature standard API on server and web, with NanoFlags evaluating locally underneath.
Docs - @nanoflags/cli
CLI
Create flags, evaluate a context, run scenarios, scan code references, export everything.
Docs - integrations/github-action
GitHub Action
Runs your scenario checks for a commit and fails the job when one fails.
Docs - github.com/apps/nanoflags
GitHub App
Flag states in a pull request comment and a “NanoFlags scenarios” check run.
Docs
History
Every revision kept. Any one restored.
Each publish creates an immutable, numbered revision. Restore loads an old revision into the draft and you publish it as a new one, so history is never rewritten.
- The audit log is written by the database, not by the browser, and it is read-only.
- Restoring a revision also brings back the segments it used.
- Export the audit log on Scale. Export the whole project as JSON from the dashboard or the CLI.
- r185current
Raise checkout-v2 to 50% in EU
lee · 12:06
- r184Restore to draft
checkout-v2 to 25% in EU
lee · 10 Nov 09:12
- r183Restore to draft
Enable new-pricing-page for internal staff
omar · 9 Nov 16:40
audit log
12:06:14leepublished r185 · production
12:04:51leeapproved change · draft 9f3c1a
12:01:09ciscenarios 4/4 passed · commit 3e1f2a0
11:58:32mayaedited draft · checkout-v2
Run your next release through it.
Explore is free. Team adds required approvals and scenario checks to protected environments.