> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useshipd.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from LaunchDarkly

> Map LaunchDarkly flags, variations, contexts, and segments to shipd, and move flags over one at a time.

## Overview

This page maps LaunchDarkly concepts to shipd and shows a manual migration path. shipd has no automated importer: you recreate flag definitions in TypeScript or Go, recreate targeting in the dashboard, and switch code over flag by flag.

## Concept mapping

| LaunchDarkly | shipd |
| - | - |
| Project / environment | Project / environment |
| Flag | Flag, defined in `shipd.config.ts` |
| Boolean flag | Boolean flag (`type: "boolean"`) |
| String flag with a fixed set of variations | Variant flag (`type: "variant"`) |
| Number flag | Number flag (`type: "number"`) |
| JSON flag | JSON flag (`type: "json"`) |
| Variations | `variants` (variant flags) or the values rules serve |
| Context (user) | [Evaluation context](/reference/sdk#types): `userId` plus `attributes` |
| Individual targets | A rule: `userId` **is one of** a list |
| Targeting rules | Rules on the flag page. First match wins |
| Percentage rollout | **Percentage** condition ([rollouts](/flags/percentage-rollouts)) ([A/B splits](/flags/experiments)) |
| Segments | Audiences |
| Default rule (fallthrough) | **Fallthrough** |
| Targeting off / off variation | No separate off variation. A disabled flag serves its **Fallthrough** value; to turn a flag off, set **Fallthrough** to the off value ([details](/flags/kill-switch)) |
| SDK key | Server SDK key (`shipd_sdk_server_…`) |
| Mobile key / client-side ID | Client SDK key (`shipd_sdk_client_…`) |
| Relay Proxy | Not needed. SDKs download a snapshot from the edge and evaluate locally |
| Code-level fallback value | Client `defaults` |

Contexts with several kinds (user, organization, device) become attributes on one evaluation context. To bucket a rollout by organization instead of user, set the percentage condition's **Of attribute** to an attribute such as `organizationId`.

Prerequisite flags have no equivalent. Express the dependency in code or in each flag's rules.

## Migrate a flag

**1. Recreate the definition**

Keep the same key so call sites are easy to find.

```ts TypeScript theme={null}
// shipd.config.ts
import { defineFlags } from "shipdit/config";

export default defineFlags({
  "new-checkout": {
    type: "boolean",
    default: false,
    description: "Migrated from LaunchDarkly",
  },
  "search-variant": {
    type: "variant",
    variants: ["control", "semantic", "hybrid"] as const,
    default: "control",
  },
});
```

```go Go theme={null}
// Entries inside config.ShipdConfig (import github.com/alasti-company/useshipd.com/sdks/go/config).
"new-checkout": {Type: "boolean", Default: false,
    Description: "Migrated from LaunchDarkly"},
"search-variant": {Type: "variant", Default: "control",
    Variants: []string{"control", "semantic", "hybrid"}},
```

**2. Push**

```bash theme={null}
shipd push --project web-app --env production
```

**3. Recreate targeting**

For each environment, open the flag in the [dashboard](https://app.useshipd.com), add rules in the same order as in LaunchDarkly, set **Fallthrough**, and click **Save environment**. Recreate segments first under **Audiences** so rules can reference them. See [Target users by attribute](/flags/targeting).

**4. Send the same attributes**

Pass the attributes your LaunchDarkly rules used (for example `email`, `plan`, `country`) in the evaluation context. See [Identify users](/flags/identify-users).

**5. Dual-run behind a wrapper**

Route evaluations through one function, compare both systems, then switch.

```ts TypeScript theme={null}
// src/lib/flags.ts
import { shipd } from "./shipd";
import { ldClient } from "./launchdarkly";

export async function newCheckoutEnabled(user: { id: string; plan: string }) {
  const fromShipd = shipd.isEnabled("new-checkout", {
    userId: user.id,
    attributes: { plan: user.plan },
  });
  const fromLd = await ldClient.variation(
    "new-checkout",
    { kind: "user", key: user.id, plan: user.plan },
    false,
  );

  if (fromShipd !== fromLd) {
    console.warn("flag mismatch", { key: "new-checkout", userId: user.id, fromShipd, fromLd });
  }
  return fromLd; // switch to fromShipd once mismatches stop
}
```

```go Go theme={null}
// flags.go
package flags

import (
	shipd "github.com/alasti-company/useshipd.com/sdks/go"
	"log"
)

// Pass a function that calls your existing LaunchDarkly client.
func newCheckoutEnabled(client *shipd.Client, userID, plan string, fromLaunchDarkly func() (bool, error)) (bool, error) {
	fromShipd := client.IsEnabled("new-checkout", shipd.EvaluationContext{
		UserID: userID, Attributes: map[string]any{"plan": plan},
	})
	fromLD, err := fromLaunchDarkly()
	if err != nil {
		return false, err
	}
	if fromShipd != fromLD {
		log.Printf("flag mismatch: key=new-checkout user=%s shipd=%v ld=%v", userID, fromShipd, fromLD)
	}
	return fromLD, nil // Switch to fromShipd once differences are acceptable.
}
```

**6. Cut over**

Return the shipd value, remove the LaunchDarkly call, and archive the flag in LaunchDarkly.

Percentage rollouts hash differently in each tool, so a user in LaunchDarkly's 20% isn't necessarily in shipd's 20%. Expect mismatches for rolled-out flags, and cut them over when the difference is acceptable.

For Go definition snippets, add the entries to `config.ShipdConfig` in `shipd.config.go` before pushing. See [Define flags in code](/config-as-code/define-flags#go-definitions).

## Related

* [Quickstart](/quickstart)
* [Define flags in code](/config-as-code/define-flags)
* [Local evaluation](/concepts/local-evaluation)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.