npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@toggld/node

v0.3.0

Published

Toggld SDK for Node.js — local flag evaluation with a background definition sync. Plain Promise API by default; native Effect API via @toggld/node/effect.

Downloads

17

Readme

@toggld/node

The Toggld SDK for Node.js. Evaluate feature flags from your backend against the Toggld flag API.

Two API surfaces ship from one implementation:

  • @toggld/node — a plain Promise API. No Effect types in any signature.
  • @toggld/node/effect — the native Effect API: the client as a service + Layer.

Two evaluation modes:

  • Remote (default) — every call hits the flag API, which evaluates the flag against your context and returns the resolved value (OpenFeature "remote evaluation" over the OFREP endpoints).
  • Local (mode: "local") — recommended for long-lived servers. Flag definitions sync in the background (a snapshot fetch plus a live WebSocket stream, with polling fallback) and every evaluation runs in-process on the bundled engine: microsecond latency, zero server requests per evaluation, and changes pushed to your process within milliseconds. Requires a secret SDK key (ffk_…) — public browser tokens cannot read rulesets. See ADR-0012. Local mode can also read its snapshot from a file instead of the network — see Local flag files below.

Install

pnpm add @toggld/node

Promise API

import { ToggldClient } from "@toggld/node"

const client = await ToggldClient.create({
  sdkKey: process.env.TOGGLD_SDK_KEY!, // an evaluation API key
  endpoint: "https://your-flag-api.example.com",
  mode: "local", // omit for remote evaluation
})

// Typed getters — return the default on any error, never throw.
const on = await client.getBooleanValue("new-checkout", false, {
  targetingKey: "user-123",
  plan: "premium",
})

// Full OpenFeature evaluation details.
const details = await client.getStringDetails("theme", "light", { targetingKey: "user-123" })
//    ^ { flagKey, value, variant, reason, errorCode, errorMessage, flagMetadata }

// All flags for the environment in one request.
const everything = await client.evaluateAll({ targetingKey: "user-123" })

await client.close() // releases the underlying runtime

Getters exist for each flag type: getBooleanValue / getBooleanDetails, getStringValue / , getNumberValue / , and getObjectValue<T> / .

Effect API

import { Effect } from "effect"
import { ToggldClient, layer } from "@toggld/node/effect"

const program = Effect.gen(function* () {
  const flags = yield* ToggldClient
  return yield* flags.getBooleanValue("new-checkout", false, { targetingKey: "user-123" })
})

program.pipe(
  Effect.provide(layer({ sdkKey, endpoint })),
  Effect.runPromise,
)

The layer is self-contained — it wires its own HTTP backend, so you only provide this one layer. Lifecycle (the HTTP client) is managed by the enclosing scope.

Options

| Option | Type | Default | Notes | | ---------------- | --------------------- | ---------------- | ---------------------------------------------------------------- | | sdkKey | string | — | Evaluation (or management) API key; sent as Bearer. | | endpoint | string | — | Base URL of the flag API, no trailing path. | | mode | "remote" \| "local" | "remote" | Local = background definition sync + in-process engine. | | sync.transport | "ws" \| "poll" | "ws" | Live stream (with poll safety net) vs polling only. | | sync.pollIntervalMs | number | 30000 | Snapshot poll cadence; cold start retries faster. | | sync.readyTimeoutMs | number | 5000 | How long create waits for the first snapshot. | | sync.file | string \| boolean | — | Read the snapshot from a local file (offline); true./toggld.flags.json. | | defaultContext | EvaluationContext | {} | Merged under per-call context (per-call attributes win). | | timeoutMs | number | 5000 | Per-request timeout. | | fetch | typeof fetch | globalThis.fetch | Custom fetch (tests, proxies, instrumentation). |

In local mode create resolves once the first snapshot has synced (or after sync.readyTimeoutMs); until a snapshot arrives, evaluations return your defaults with errorCode: "PROVIDER_NOT_READY" and sync keeps retrying. client.ready() awaits sync explicitly. Updates arrive as WebSocket pushes within milliseconds of a management change; on runtimes where the stream is unavailable the client polls instead, automatically.

How fast is local mode?

pnpm bench:sync (from the repo root) runs the same workload with sync off vs on — representative numbers on a laptop, loopback server:

sync OFF (remote OFREP)        ~11,600 evals/s   p50 2.4 ms
sync ON  (local engine)     ~1,090,000 evals/s   p50 27 µs   (0.6 µs single-caller)

Local flag files (offline)

For local development, CI, or offline runs, a client can evaluate against a file instead of syncing over the network — same engine, same results, no flag API required. Generate the file with the bundled CLI:

# Fetch the environment's current flags into ./toggld.flags.json.
# Prompts for the key if you omit --sdk-key (or set TOGGLD_SDK_KEY).
npx @toggld/node pull --sdk-key ffk_… --api https://your-flag-api.example.com

Then point a client at it — no sdkKey or endpoint needed:

const client = await ToggldClient.create({
  mode: "local",
  sync: { file: "./toggld.flags.json" }, // or `file: true` for that default path
})

The file is a FlagSnapshot (the exact wire snapshot the SDK syncs) wrapped in a small provenance envelope, so it is human-readable, diffable, and editable — flip an enabled, nudge a rollout, commit a fixture. Edits are picked up live (the file is watched); no restart.

You can also redirect any client to a file with no code change by setting TOGGLD_FLAGS_FILE — it overrides the network source even under the default remote mode:

TOGGLD_FLAGS_FILE=./toggld.flags.json node server.js

pull needs a secret key (ffk_…); it is one-shot and idempotent (an unchanged version is not rewritten — pass --force to override). See ADR-0013. Remote-segment membership (ADR-0006) is not yet available offline; a file-backed client warns once and treats a remote segment's non-rule-matched subjects as non-members.

Error semantics

Evaluation never throws. On a network failure, timeout, unknown flag, server error, or a value whose type doesn't match the requested getter, the call resolves to your default value. The *Details methods carry reason: "ERROR" and an OpenFeature errorCode (FLAG_NOT_FOUND, TYPE_MISMATCH, TARGETING_KEY_MISSING, PARSE_ERROR, GENERAL, …) describing what happened.