FeatureSignals

Migrate from LaunchDarkly

Follow this step-by-step guide to migrate your feature flags from LaunchDarkly to FeatureSignals. The process takes most teams under an hour. You can run the import against a staging environment first to validate without risk.

Before you start

Make sure you have an active FeatureSignals account, a project and environment set up, and a LaunchDarkly API access token with read access. See Quickstart if you haven't created your first project yet.

  1. 1. Export flags from LaunchDarkly

    Use the FeatureSignals migration CLI to pull a complete flag snapshot from LaunchDarkly. The CLI uses the LaunchDarkly REST API to export all flags, segments, and environments.

    bash
    # Install the FeatureSignals migration CLI
    npm install -g @featuresignals/migration-cli
    
    # Export all flags from LaunchDarkly
    fs-migrate export launchdarkly \
      --api-token "$LD_API_TOKEN" \
      --project-key "my-project" \
      --output ./ld-export.json

    The export file contains all boolean flags, multivariate flags, targeting rules, segments, and rollout configurations. The CLI preserves the LaunchDarkly project and environment structure for mapping in the next step.

  2. 2. Transform flags to FeatureSignals format

    Run the transform command to map LaunchDarkly entities to FeatureSignals equivalents. The migration engine handles:

    • Boolean flags → boolean flag type
    • Multivariate flags → ab flag type with variants
    • Targeting rules → FeatureSignals targeting rules
    • Segments → FeatureSignals segments
    • Environments → FeatureSignals environments
    • Percentage rollouts → FeatureSignals percentage rollout
    bash
    # Transform the LaunchDarkly export to FeatureSignals format
    fs-migrate transform launchdarkly \
      --input ./ld-export.json \
      --output ./fs-import.json \
      --project-id "$FS_PROJECT_ID" \
      --environment-mapping "production:prod,staging:staging,development:dev"

    A preview report is generated showing flags that will be created, updated, or skipped. Review this report carefully before importing.

  3. 3. Import flags to FeatureSignals

    Import the transformed flags into your FeatureSignals project. The import is transactional — if any flag creation fails, the entire batch is rolled back.

    bash
    # Import to FeatureSignals (staging environment first)
    fs-migrate import \
      --input ./fs-import.json \
      --api-key "$FS_API_KEY" \
      --base-url "https://api.featuresignals.com" \
      --target-environment "staging"

    Tip: Import to staging first. Validate everything looks correct, then run the import again targeting your production environment.

  4. 4. Validate parity between platforms

    Run the validation engine to confirm flag evaluations produce identical results in both LaunchDarkly and FeatureSignals. The validator evaluates each flag with a representative sample of user contexts and compares the results.

    bash
    # Validate evaluation parity
    fs-migrate validate \
      --source launchdarkly \
      --source-api-token "$LD_API_TOKEN" \
      --target featuresignals \
      --target-api-key "$FS_API_KEY" \
      --sample-size 100

    The validation report shows a pass/fail for each flag and a summary of any discrepancies. Address any mismatches before proceeding to the cutover.

  5. 5. Cut over your SDKs

    With your flags imported and validated, switch your SDK initialization from LaunchDarkly to FeatureSignals. If you're using OpenFeature (recommended), this is a one-line change:

    typescript
    // Before: LaunchDarkly provider
    OpenFeature.setProvider(new LaunchDarklyProvider({ clientSideID: '...' }));
    
    // After: FeatureSignals provider
    OpenFeature.setProvider(new FeatureSignalsProvider({
      environmentKey: 'env_your_key_here',
    }));
    
    // The rest of your flag evaluation code stays the same
    const client = OpenFeature.getClient();
    const myFlag = await client.getBooleanValue('my-flag', false, { targetKey: user.id });

    See the SDK documentation for language-specific initialization examples. After cutover, keep LaunchDarkly as read-only for a week as a safety net, then decommission.

Next Steps