Skip to content
NanoFlags
Start free

Developers

Evaluate locally.Verify everything.

One small SDK for browsers and Node.js, with React hooks and an OpenFeature provider. A CLI and GitHub integrations for CI and pull requests. The code that runs in your app is Apache-2.0, and every bundle it receives is signed.

@nanoflags/sdk 0.4.0Apache-2.0No runtime dependenciesNode 18+ · browsers · edge runtimes

Quickstart

Three steps to your first flag.

Create a free project, copy an SDK key from Settings → Keys, then:

  1. Install the SDK

    ESM and CommonJS builds with TypeScript types. React is an optional peer dependency.

    terminal
    npm install @nanoflags/sdk
  2. Create one client

    One client per process. It loads the bundle, opens the live connection and verifies signatures in the background.

    flags.ts
    import { createClient } from "@nanoflags/sdk";
    
    export const flags = createClient({
      sdkKey: process.env.NANOFLAGS_SDK_KEY!,   // nf_srv_… (server) or nf_pub_… (browser)
      baseUrl: "https://edge.nanoflags.io",
      service: "checkout-api",
    });
    
    await flags.ready(); // never rejects
  3. Read a flag

    Accessors are local and synchronous. They never perform I/O and never throw: without a bundle they return your fallback.

    checkout.ts
    const on = flags.boolean("checkout-v2", false, { key: user.id, region: "EU" });
    // Local and synchronous. Returns false only if no configuration has ever loaded.
Full quickstart

SDK

The same engine in every runtime.

The SDK bundles the evaluation engine the edge, the CLI and CI run, so a result in your test is the result in production. Pick a runtime:

  • Signatures verified by default on the official edge (SDK 0.4.0+), with the production keys embedded.
  • Live updates over one WebSocket; server-sent events and polling as fallbacks.
  • ready() never rejects; status tells you ready, stale or not-ready.
  • Browser keys receive only client-exposed flags.
import { createClient } from "@nanoflags/sdk";

const flags = createClient({
  sdkKey: process.env.NANOFLAGS_SDK_KEY!,
  baseUrl: "https://edge.nanoflags.io",
  service: "checkout-api",
});
await flags.ready();

const result = flags.evaluate("checkout-v2", false, { key: user.id, region: "EU" });
// { value, reason: "rule_match", ruleIndex: 1, inRollout: true, bucket: 37.12, revision: 184 }

flags.on("update", (u) => console.log("r" + u.revision, u.transport, u.latencyMs));

OpenFeature

Keep your call sites standard.

The OpenFeature provider wraps a NanoFlags client for the server SDK and the web SDK. Evaluation stays local inside the provider; NanoFlags keeps doing the loading and the live updates. Your flag calls use the OpenFeature standard API.

Install

npm i @nanoflags/openfeature-providerOpenFeature guide
import { OpenFeature } from "@openfeature/server-sdk";
import { createClient } from "@nanoflags/sdk";
import { NanoFlagsProvider } from "@nanoflags/openfeature-provider/server";

const nanoflags = createClient({ sdkKey: process.env.NANOFLAGS_SDK_KEY!, baseUrl: "https://edge.nanoflags.io" });
await OpenFeature.setProviderAndWait(new NanoFlagsProvider({ client: nanoflags }));

const on = await OpenFeature.getClient().getBooleanValue("checkout-v2", false, { targetingKey: user.id });

CLI

Flags from the terminal and from CI.

@nanoflags/cli works with a CI key (export, scenarios, code references) or an admin key (all of that, plus creating flags and publishing). SDK keys are refused.

  • nanoflags flags create <key> --type boolean

    Create a flag with a type, default, name and description.

  • nanoflags eval <flag> --context '{…}'

    Evaluate a context against the draft or the published revision, with the reason and the trace.

  • nanoflags scenarios run --source draft

    Run scenario checks for a commit; exit code 1 when one fails.

  • nanoflags refs scan . --repo owner/name

    Find flag references in your code and upload them.

  • nanoflags publish --expected-revision <n>

    Publish the draft, following the environment's policy.

  • nanoflags export --out project.json

    Export the whole project as JSON.

Pass the key in NANOFLAGS_KEY, not as an argument: arguments are visible in process lists and shell history.

Install

npm i -g @nanoflags/cli
terminal
export NANOFLAGS_KEY=nf_adm_…          # admin key: create flags, publish

nanoflags flags create new-checkout --description "New checkout flow"
nanoflags flags create search-limit --type number --default 25

nanoflags eval checkout-v2 --context '{"key":"user_42","region":"EU"}'
# checkout-v2 = true
# reason: rule_match · rule r2 (#2) · inside rollout (bucket 37.12)
# source: draft of production
CLI reference

GitHub

Flag checks where the code is reviewed.

Two ways to bring NanoFlags into pull requests: an Action you add to a workflow, and an App you install once.

GitHub Action

Runs your scenario checks for a commit and fails the job when one fails; optionally uploads code references. Use a CI key: it can run scenarios but can't publish, and the action refuses admin keys.

.github/workflows/flags.yml
name: Flags
on:
  pull_request:          # NOT pull_request_target
  push:
    branches: [main]
permissions:
  contents: read
jobs:
  scenarios:
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - uses: motazalmaroai/nanoflags-sdk/integrations/github-action@main   # pin to a commit SHA
        with:
          key: ${{ secrets.NANOFLAGS_CI_KEY }}
          source: draft
CI guide

GitHub App

  • A pull request comment with the state of every flag the change references, edited in place.
  • A “NanoFlags scenarios” check run against the draft or published revision you choose.
  • Code references from your default branch, and cleanup hints for flags nobody reads.
GitHub App guide

Verify it yourself

Signed bundles, public keys.

Every published revision is signed with Ed25519 before it is distributed. The public keys are served without authentication, so you can check a bundle with nothing but curl and your own code.

  1. Fetch the public keys

    A JSON list of JWKs, each with a kid and a status. During a rotation the old key is listed as retiring.

  2. Read the signature headers

    The edge sends the signature, the key id and the environment id with every signed bundle.

  3. Verify the canonical string

    Ed25519 over the string below, where the last line is the SHA-256 of the bundle text exactly as sent. The SDK does exactly this.

Signature format
terminal
# 1. Public signing keys (no authentication)
curl -s https://edge.nanoflags.io/v1/keys
# {"keys":[{"kty":"OKP","crv":"Ed25519","x":"…","kid":"k1","alg":"EdDSA","use":"sig","status":"active"}]}

# 2. A signed bundle and its signature headers
curl -s -D headers.txt -o bundle.json \
  -H "Authorization: Bearer $NANOFLAGS_SDK_KEY" https://edge.nanoflags.io/v1/bundle
grep -i '^x-nanoflags-' headers.txt
# X-NanoFlags-Signed: true
# X-NanoFlags-Key-Id: k1
# X-NanoFlags-Signature: …
# X-NanoFlags-Environment-Id: …

# 3. Ed25519 signature over this canonical string
nanoflags-bundle-v1
<environment id>
<revision>
<checksum>
<sha256 hex of bundle.json, byte for byte>

Start with one flag.

Explore is free: one project, three environments, the full SDK and CLI.