Migrating from LaunchDarkly: A Technical Guide with Zero Downtime
A complete migration playbook covering the full 5-step process: discover providers, validate credentials, dry-run analysis, execute import, and monitor progress. We walk through operator mapping (13 operators, negation support), segment migration, environment handling, IaC export for GitOps, and post-migration verification — with real API calls and configuration snippets.
Why Teams Migrate
We've helped dozens of teams migrate from LaunchDarkly to FeatureSignals. The reasons are consistent: pricing that scales unpredictably with MAU (monthly active users), a desire for self-hosted infrastructure to satisfy data sovereignty requirements, frustration with proprietary SDK lock-in, and a preference for open-source tooling with community-driven development. One team we worked with was paying $72,000/year for LaunchDarkly and migrated to a self-hosted FeatureSignals instance running on a $200/month cloud server with better evaluation latency.
Migration sounds daunting — flags, segments, environments, SDK integrations, CI/CD pipelines — but with the right process, it's a methodical operation that can be completed without any application downtime, any broken flags, or any user impact. This guide walks through exactly how to do it.
Pre-Migration Checklist
Before you start the migration, complete this checklist. Missing items here are the most common source of migration issues:
- Inventory your flags: Export a complete list from LaunchDarkly. Note which flags are active, which are deprecated but still referenced in code, and which can be archived.
- Map your environments: LaunchDarkly environments → FeatureSignals environments. The names don't need to match, but the mapping must be documented. Most teams use 1:1 mapping (production→production, staging→staging).
- Audit your SDK usage: Which languages? Which versions? Are you using LaunchDarkly-specific features like prerequisite flags, percentage rollouts with custom attributes, or experimentation?
- Identify custom integrations: Webhooks, audit log streaming, Slack notifications, Datadog metrics. These need to be reconfigured post-migration.
- Set up your FeatureSignals instance: Deploy the server (self-hosted or cloud). Create your organization, project, and environments. Generate API keys.
- Run the migration in staging first: Never migrate production first. Use staging to validate the process, then repeat for production.
The 5-Step Migration Process
We've refined the migration process into five discrete steps. Each step is independently verifiable, so you can pause, validate, and resume without starting over.
- Discover: The migration tool connects to your LaunchDarkly account via API key and enumerates all flags, segments, environments, and targeting rules. Nothing is modified at this stage — it's a read-only inventory.
- Validate: The tool checks every flag and rule for compatibility with FeatureSignals. It flags unsupported operators, identifies flags that need manual attention, and generates a compatibility report.
- Dry-Run: The tool simulates the migration, creating a preview of what the FeatureSignals configuration will look like. No data is written. Review the preview carefully.
- Execute: The tool creates flags, segments, and targeting rules in FeatureSignals. This is idempotent — you can run it multiple times and it won't create duplicates.
- Monitor: After migration, run both systems in parallel (dual-read) for 48–72 hours. Compare evaluation results between LaunchDarkly and FeatureSignals to catch any discrepancies before cutting over.
Operator Mapping: LD → FeatureSignals
FeatureSignals supports all standard LaunchDarkly operators plus several extensions. Here's the complete mapping:
Operator Mapping Reference
LD Operator → FS Operator Notes
─────────────────────────────────────────────────────────
in → in Direct equivalent
endsWith → endsWith Direct equivalent
startsWith → startsWith Direct equivalent
matches → matches Regex matching
contains → contains Substring matching
lessThan → lessThan Numeric comparison
lessThanOrEqual → lessThanOrEqual Numeric comparison
greaterThan → greaterThan Numeric comparison
greaterThanOrEqual → greaterThanOrEqual Numeric comparison
before → before Date comparison
after → after Date comparison
segmentMatch → segmentMatch Segment membership
semVerEqual → semVerEqual SemVer comparison (FS extension)
semVerLessThan → semVerLessThan SemVer comparison (FS extension)
semVerGreaterThan → semVerGreaterThan SemVer comparison (FS extension)
percentage → percentage MurmurHash3-based rolloutPercentage Rollout Conversion
Percentage rollouts work identically in both systems — hash the user key, modulo 100, compare to the rollout percentage. However, LaunchDarkly uses a different hashing algorithm than FeatureSignals (one based on a CRC-like function vs. our MurmurHash3). This means the same user may fall into different buckets across the two systems during the dual-read phase. This is expected and not a problem — the distribution is still uniform at scale. What matters is that both systems serve the correct variation for the bucket the user lands in, not that the buckets are identical.
Infrastructure as Code: Terraform Export
For teams practicing GitOps, the migration tool can export your entire FeatureSignals configuration as Terraform HCL. This gives you version-controlled, reviewable flag configuration that integrates with your existing CI/CD pipeline:
# Generated by FeatureSignals Migration Tool v2.4.0
# Source: LaunchDarkly project "acme-platform" (production)
resource "featuresignals_flag" "new_checkout" {
project_key = "acme-platform"
env_key = "production"
key = "new-checkout"
name = "New Checkout Flow"
description = "Migrated from LaunchDarkly — rollout completed 2026-02-15"
type = "boolean"
default_variation = "off"
variations = [
{ name = "on", value = true },
{ name = "off", value = false },
]
rules {
description = "Internal users"
priority = 1
variation = "on"
conditions {
attribute = "email"
operator = "endsWith"
value = "@acme-corp.com"
}
}
rules {
description = "10% gradual rollout"
priority = 2
variation = "on"
conditions {
attribute = "key"
operator = "percentage"
value = "10"
}
}
}Dual-Read Verification Pattern
The safest migration pattern is dual-read: run both LaunchDarkly and FeatureSignals in parallel and compare results. Here's the pattern in Go:
// DualRead evaluates a flag against both the existing LD client
// and the new FeatureSignals client, logs any mismatches, and
// returns the LaunchDarkly result (safe: no behavior change).
func DualRead(
ldClient *ldclient.LDClient,
fsClient openfeature.IClient,
flagKey string,
user lduser.User,
) bool {
ctx := context.Background()
// Evaluate against both systems concurrently
var ldResult, fsResult bool
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
ldResult, _ = ldClient.BoolVariation(flagKey, user, false)
}()
go func() {
defer wg.Done()
fsResult, _ = fsClient.BooleanValue(ctx, flagKey, false,
openfeature.NewEvaluationContext(
user.GetKey(),
map[string]interface{}{
"email": user.GetEmail(),
"name": user.GetName(),
},
),
)
}()
wg.Wait()
// Log mismatches for investigation
if ldResult != fsResult {
slog.Warn("dual-read mismatch",
"flag", flagKey,
"user", user.GetKey(),
"ld_result", ldResult,
"fs_result", fsResult,
)
}
// Return the existing behavior — FeatureSignals is shadowing only
return ldResult
}Run the dual-read pattern for 48–72 hours. Monitor the mismatch rate. A mismatch rate under 1% is typical during migration (caused by percentage rollout hash differences, timing differences in flag updates, and edge cases in operator semantics). If the mismatch rate is higher, investigate before cutting over.
Post-Migration: SDK Swap and Cleanup
Once you've validated the dual-read results and are confident in the migration, swap the SDK and decommission LaunchDarkly:
- Swap the provider: Replace the LaunchDarkly provider with the FeatureSignals OpenFeature provider in your application initialization. If you're not using OpenFeature yet, this is the time to adopt it.
- Remove dual-read code: Delete the shadow evaluation logic and use FeatureSignals as the sole source of truth.
- Decommission LaunchDarkly: Export your final audit log. Archive the project. Cancel the subscription.
- Monitor: Watch your FeatureSignals dashboards for the first 24 hours. Check evaluation latency, error rates, and flag resolution accuracy.
- Celebrate: You're now running on open-source, sub-millisecond feature flags with no vendor lock-in.
Tip
Keep your LaunchDarkly account active for 30 days post-migration as a safety net. If something goes wrong, you can revert the provider swap and be back on LaunchDarkly in minutes. We've never seen a team need this, but it's cheap insurance.