Find every direct LaunchDarkly SDK call. Migrate safely. Enforce the boundary.
Most teams do not know how many direct LaunchDarkly SDK calls are in their codebase, which ones are safe to migrate, or which ones will silently break if migrated naively. FlagLint answers all three questions before you touch a line of code.
npx flaglint audit ./src✓ Audit complete: 13 unique flags across 19 call sites — 3 high risk, 10 medium risk
Migration readiness: 53/100 · moderate
[█████████████░░░░░░░░░░░░] 53%
10 of 19 call sites safely automatable · 9 require manual review
Add --effort-estimate to include a directional planning estimate:
npx flaglint audit ./src --effort-estimate✓ Audit complete: 13 unique flags across 19 call sites — 3 high risk, 10 medium risk
Migration readiness: 53/100 · moderate
[█████████████░░░░░░░░░░░░] 53%
10 of 19 call sites safely automatable · 9 require manual review
Estimated migration effort: 20.8h – 40h
Estimates are directional. See the report for assumptions.
For the full report see --format html. Documentation · Quickstart · npm
No API key. No source upload. LaunchDarkly stays your provider — OpenFeature becomes the evaluation API your application calls.
Migrating an existing Node.js service? Read the complete LaunchDarkly-to-OpenFeature migration guide.
The OpenFeature getBooleanValue(key, defaultValue, context) API takes arguments in a different order from LaunchDarkly's boolVariation(key, context, defaultValue). A naive find-and-replace silently swaps your fallback and context, producing valid-looking code that evaluates flags incorrectly in production.
FlagLint's static analysis proves — before rewriting anything — that the flag key is static, the fallback value and type are known, and a verified OpenFeature client binding is present. If any condition cannot be proven, the call is reported for manual review and left untouched.
| Step | Command | What it does |
|---|---|---|
| 1 | flaglint audit ./src |
Risk-ranked overview. High / medium / low per flag. No API key needed. |
| 2 | flaglint scan ./src |
Detailed file-level structured inventory for automation or review. |
| 3 | flaglint migrate ./src --dry-run |
Reviewable before/after diffs. Shows exactly what will change. |
| 4 | flaglint migrate ./src --apply |
Rewrites only calls with proven static inputs and a verified OpenFeature binding. |
| 5 | flaglint validate ./src --no-direct-launchdarkly |
CI gate — exits 1 if any direct LD evaluation call remains. |
--- a/src/routes/checkout.ts
+++ b/src/routes/checkout.ts
- return ldClient.boolVariation("checkout-v2", ctx, false);
+ return openFeatureClient.getBooleanValue("checkout-v2", false, ctx);
- return ldClient.stringVariation("payment-provider", ctx, "stripe");
+ return openFeatureClient.getStringValue("payment-provider", "stripe", ctx);
--- a/src/services/pricing.ts
+++ b/src/services/pricing.ts
- return ldClient.numberVariation("discount-percentage", ctx, 0);
+ return openFeatureClient.getNumberValue("discount-percentage", 0, ctx);Flag key, fallback value, evaluation context, and await are preserved exactly. The LaunchDarkly packages stay — the OpenFeature provider depends on them at runtime.
FlagLint is intentionally conservative. These are always skipped and reported for manual review:
- Dynamic keys —
ldClient.boolVariation(getFlagKey(user), ctx, false) - Detail evaluations —
boolVariationDetail,variationDetail - Bulk calls —
allFlags(),allFlagsState() - Unknown fallback types
- Configured wrappers
- Ambiguous OpenFeature client bindings
- Browser SDKs, React SDKs, non-Node SDKs
LaunchDarkly Node.js server-side SDK calls from @launchdarkly/node-server-sdk and launchdarkly-node-server-sdk. Both ESM and CommonJS. Node.js 20 or newer.
Full coverage table: Supported Scope
Before migrate --apply, complete provider bootstrap once:
import { OpenFeature } from "@openfeature/server-sdk";
import { LaunchDarklyProvider } from "@launchdarkly/openfeature-node-server";
await OpenFeature.setProviderAndWait(
new LaunchDarklyProvider(process.env.LD_SDK_KEY!)
);
export const openFeatureClient = OpenFeature.getClient();Evaluation context accepts either targetingKey (OpenFeature-native) or an existing LaunchDarkly key. Do not remove LaunchDarkly packages — the OpenFeature provider depends on them at runtime.
Full instructions: OpenFeature Provider Setup
FlagLint runs entirely on your machine. No source code, flag keys, or file paths leave your environment. No LaunchDarkly API key or credentials are required for audit, scan, migrate, or validate.
Docs · Quickstart · Blog · Security · Contributing · Changelog · License