# SDK version tracking

Track which SDK versions are deployed across your projects and environments to maintain security, compatibility, and access to the latest features.

## Why track SDK versions

Tracking SDK versions helps you:
- Identify outdated SDKs that may have security vulnerabilities
- Understand which SDKs are approaching end-of-life
- Plan SDK upgrade initiatives across your organization
- Monitor relay proxy versions alongside client SDKs
- Maintain compliance with security policies

## SDK versions API endpoint

LaunchDarkly provides a dedicated API endpoint to retrieve detailed SDK version usage data. The endpoint returns one record per unique SDK and project/environment combination, representing the maximum version observed in the last day.

### Endpoint details

**Endpoint:**
```
GET https://app.launchdarkly.com/api/v2/usage/sdk-versions/details
```

**Authentication:**
The endpoint requires an API access token with appropriate permissions. Include the token in the Authorization header.

**Beta API header:**
This endpoint is currently in beta. Include the `LD-API-Version: beta` header in your requests:
```bash
curl -H "Authorization: api-your-access-token" \
     -H "LD-API-Version: beta" \
     https://app.launchdarkly.com/api/v2/usage/sdk-versions/details
```

**Data refresh:**
The endpoint refreshes hourly and returns the maximum version for each SDK observed in the last day.

### Response data

The endpoint returns an array of SDK version records. Each record includes:

| Field | Description |
|-------|-------------|
| `name` | SDK name |
| `version` | Observed SDK version |
| `type` | SDK type |
| `projectId` | Project identifier |
| `projectKey` | Project key |
| `projectName` | Project display name |
| `environmentId` | Environment identifier |
| `environmentKey` | Environment key |
| `environmentName` | Environment display name |
| `applicationId` | Application identifier if available |
| `ldLatestVersion` | Latest available minor version from LaunchDarkly (truncated semver, e.g. `9.11`). May be empty if the SDK type is unrecognized. The installed version may legitimately exceed this value while still showing `EolAllClear`. |
| `eolStatus` | End-of-life status. Possible values: `EolAllClear` (supported), `EolUnknown` (SDK type not recognized), `EolPast` (past end-of-life), `MajorVersionAvailable` (new major version available, upgrade recommended) |
| `latestReleaseUrl` | URL to latest SDK release |
| `connectionType` | Connection type. Possible values: `direct`, `relay` |
| `relayVersion` | Relay proxy version if connected through relay |
| `relayEolStatus` | Relay proxy end-of-life status |
| `relayLatestVersion` | Latest available relay proxy version |
| `relayLatestReleaseUrl` | URL to latest relay proxy release |

### Example requests

**Python:**
```python
import requests

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

for sdk in sdk_versions:
    print(f"{sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
    if sdk.get('eolStatus'):
        print(f"  EOL Status: {sdk['eolStatus']}")
```

**JavaScript:**
```javascript
const url = 'https://app.launchdarkly.com/api/v2/usage/sdk-versions/details';
const options = {
  method: 'GET',
  headers: {
    'Authorization': 'api-your-access-token',
    'LD-API-Version': 'beta'
  }
};

async function main() {
  const response = await fetch(url, options);
  const sdkVersions = await response.json();

  sdkVersions.forEach(sdk => {
    console.log(`${sdk.name} v${sdk.version} in ${sdk.projectKey}/${sdk.environmentKey}`);
    if (sdk.eolStatus) {
      console.log(`  EOL Status: ${sdk.eolStatus}`);
    }
  });
}

main().catch(console.error);
```

**Go:**
```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "io"
)

type SDKVersion struct {
    Name            string `json:"name"`
    Version         string `json:"version"`
    ProjectKey      string `json:"projectKey"`
    EnvironmentKey  string `json:"environmentKey"`
    EOLStatus       string `json:"eolStatus"`
    LatestVersion   string `json:"ldLatestVersion"`
}

func main() {
    url := "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"

    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Printf("error creating request: %v\n", err)
        return
    }
    req.Header.Add("Authorization", "api-your-access-token")
    req.Header.Add("LD-API-Version", "beta")

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Printf("error making request: %v\n", err)
        return
    }
    defer res.Body.Close()

    if res.StatusCode != http.StatusOK {
        fmt.Printf("unexpected status: %d\n", res.StatusCode)
        return
    }

    body, err := io.ReadAll(res.Body)
    if err != nil {
        fmt.Printf("error reading response: %v\n", err)
        return
    }

    var versions []SDKVersion
    if err := json.Unmarshal(body, &versions); err != nil {
        fmt.Printf("error parsing response: %v\n", err)
        return
    }

    for _, sdk := range versions {
        fmt.Printf("%s v%s in %s/%s\n", sdk.Name, sdk.Version, sdk.ProjectKey, sdk.EnvironmentKey)
        if sdk.EOLStatus != "" {
            fmt.Printf("  EOL Status: %s\n", sdk.EOLStatus)
        }
    }
}
```

## Use cases

### Identify outdated SDKs

Query the API to find SDKs running behind the latest available version. Because `ldLatestVersion` uses truncated semver (for example `9.11` rather than `9.11.0`), a simple string comparison is unreliable — use a tuple comparison to avoid false positives when the installed version is a newer patch:

```python
import requests

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

def parse_version(v):
    try:
        return tuple(int(x) for x in v.split('.'))
    except (ValueError, AttributeError):
        return (0,)

response = requests.get(url, headers=headers)
sdk_versions = response.json()

outdated_sdks = [
    sdk for sdk in sdk_versions
    if sdk.get('ldLatestVersion')
    and parse_version(sdk.get('version', '')) < parse_version(sdk['ldLatestVersion'])
]

print(f"Found {len(outdated_sdks)} outdated SDK instances")
for sdk in outdated_sdks:
    print(f"  {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
    print(f"    Latest: v{sdk['ldLatestVersion']}")
    print(f"    Release: {sdk['latestReleaseUrl']}")
```

### Monitor end-of-life SDKs

Identify SDKs approaching or past their end-of-life:

```python
import requests

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

EOL_CLEAR = {'EolAllClear', 'EolUnknown', ''}

eol_sdks = [
    sdk for sdk in sdk_versions
    if sdk.get('eolStatus') and sdk['eolStatus'] not in EOL_CLEAR
]

print(f"Found {len(eol_sdks)} SDKs with EOL concerns")
for sdk in eol_sdks:
    print(f"  {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
    print(f"    Status: {sdk['eolStatus']}")
```

### Track relay proxy versions

Monitor relay proxy versions across your infrastructure:

```python
import requests

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

relay_connections = [
    sdk for sdk in sdk_versions 
    if sdk.get('relayVersion')
]

print(f"Found {len(relay_connections)} SDKs connected through relay proxy")
for sdk in relay_connections:
    print(f"  {sdk['name']} v{sdk['version']} in {sdk['projectKey']}/{sdk['environmentKey']}")
    print(f"    Relay: v{sdk['relayVersion']}")
    if sdk.get('relayEolStatus'):
        print(f"    Relay EOL Status: {sdk['relayEolStatus']}")
```

### Generate upgrade reports

Create comprehensive reports for SDK upgrade planning:

```python
import requests
from collections import defaultdict

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

# Group by SDK name
sdks_by_name = defaultdict(list)
for sdk in sdk_versions:
    sdks_by_name[sdk['name']].append(sdk)

# Generate report
print("SDK Upgrade Report")
print("=" * 80)

for sdk_name, instances in sdks_by_name.items():
    versions = set(inst['version'] for inst in instances)
    latest = instances[0].get('ldLatestVersion', 'Unknown')
    
    print(f"\n{sdk_name}")
    print(f"  Versions in use: {', '.join(sorted(versions))}")
    print(f"  Latest available: {latest}")
    print(f"  Total instances: {len(instances)}")
    
    # Count by environment
    envs = defaultdict(int)
    for inst in instances:
        envs[f"{inst['projectKey']}/{inst['environmentKey']}"] += 1
    
    print(f"  Deployments:")
    for env, count in sorted(envs.items()):
        print(f"    {env}: {count}")
```

## Automation

### Scheduled monitoring with PagerDuty notifications

Set up scheduled jobs to monitor SDK versions and create PagerDuty events. This example creates one event per SDK type that needs attention:

```python
import requests
from collections import defaultdict

def check_sdk_versions():
    """Check SDK versions and create PagerDuty events for outdated SDKs"""
    url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
    headers = {
        "Authorization": "api-your-access-token",
        "LD-API-Version": "beta"
    }
    
    response = requests.get(url, headers=headers)
    sdk_versions = response.json()
    
    # Group issues by SDK type
    issues_by_sdk = defaultdict(list)
    
    for sdk in sdk_versions:
        sdk_name = sdk['name']
        
        # Check for EOL status
        if sdk.get('eolStatus') and sdk['eolStatus'] not in ['EolAllClear', 'EolUnknown']:
            issues_by_sdk[sdk_name].append({
                'type': 'eol',
                'version': sdk['version'],
                'project': sdk['projectKey'],
                'environment': sdk['environmentKey'],
                'status': sdk['eolStatus']
            })
        
        # Check for outdated versions
        elif sdk.get('ldLatestVersion') and sdk.get('version') != sdk.get('ldLatestVersion'):
            issues_by_sdk[sdk_name].append({
                'type': 'outdated',
                'version': sdk['version'],
                'latest': sdk['ldLatestVersion'],
                'project': sdk['projectKey'],
                'environment': sdk['environmentKey']
            })
    
    # Create one PagerDuty event per SDK type with issues
    for sdk_name, issues in issues_by_sdk.items():
        create_pagerduty_event(sdk_name, issues)

def create_pagerduty_event(sdk_name, issues):
    """Create a PagerDuty Events API v2 event for a specific SDK type"""
    
    # Determine severity based on issue types
    has_eol = any(issue['type'] == 'eol' for issue in issues)
    severity = 'error' if has_eol else 'warning'
    
    # Build summary and details
    summary = f"{sdk_name}: {len(issues)} instance(s) need updating"
    
    # Group issues by type
    eol_issues = [i for i in issues if i['type'] == 'eol']
    outdated_issues = [i for i in issues if i['type'] == 'outdated']
    
    details = {
        'sdk_name': sdk_name,
        'total_issues': len(issues),
        'eol_count': len(eol_issues),
        'outdated_count': len(outdated_issues),
        'issues': issues
    }
    
    # Build custom details for better context
    custom_details = {}
    if eol_issues:
        custom_details['eol_instances'] = [
            f"{i['project']}/{i['environment']}: v{i['version']} ({i['status']})"
            for i in eol_issues[:5]  # Limit to first 5
        ]
    if outdated_issues:
        custom_details['outdated_instances'] = [
            f"{i['project']}/{i['environment']}: v{i['version']} (latest: v{i['latest']})"
            for i in outdated_issues[:5]  # Limit to first 5
        ]
    
    # PagerDuty Events API v2 payload
    payload = {
        'routing_key': 'your-integration-key-here',
        'event_action': 'trigger',
        'dedup_key': f'launchdarkly-sdk-{sdk_name.lower().replace(" ", "-")}',
        'payload': {
            'summary': summary,
            'severity': severity,
            'source': 'LaunchDarkly SDK Version Monitor',
            'custom_details': custom_details
        },
        'links': [
            {
                'href': 'https://app.launchdarkly.com',
                'text': 'LaunchDarkly Dashboard'
            }
        ]
    }
    
    # Send to PagerDuty Events API v2
    pagerduty_url = 'https://events.pagerduty.com/v2/enqueue'
    response = requests.post(pagerduty_url, json=payload)
    
    if response.status_code == 202:
        print(f"✓ PagerDuty event created for {sdk_name}")
    else:
        print(f"✗ Failed to create PagerDuty event for {sdk_name}: {response.text}")

# Run this script on a schedule using cron or similar
check_sdk_versions()
```

**Example PagerDuty events created:**

When this script runs against an account with outdated SDKs, it creates separate events:

1. **Python Server SDK event**:
   - Summary: "Python Server SDK: 3 instance(s) need updating"
   - Severity: warning
   - Custom details showing which projects/environments need updates

2. **React SDK event**:
   - Summary: "React SDK: 5 instance(s) need updating"
   - Severity: warning
   - Lists outdated instances

3. **.NET Server SDK event**:
   - Summary: ".NET Server SDK: 1 instance(s) need updating"
   - Severity: error (if EOL)
   - Shows EOL status and affected deployments

**Key features:**
- **Deduplication**: Uses `dedup_key` per SDK type to prevent alert fatigue
- **Severity mapping**: EOL SDKs trigger `error`, outdated SDKs trigger `warning`
- **Rich context**: Custom details show specific projects and environments affected
- **Actionable**: Each alert focuses on a single SDK type for clear ownership

### CI/CD integration

Integrate SDK version checks into your CI/CD pipeline:

```yaml
# GitHub Actions example
name: Check SDK Versions

on:
  schedule:
    - cron: '0 9 * * 1'  # Weekly on Monday at 9 AM
  workflow_dispatch:

jobs:
  check-versions:
    runs-on: ubuntu-latest
    steps:
      - name: Check SDK Versions
        run: |
          response=$(curl -s \
            -H "Authorization: ${{ secrets.LD_API_TOKEN }}" \
            -H "LD-API-Version: beta" \
            https://app.launchdarkly.com/api/v2/usage/sdk-versions/details)
          
          echo "$response" | jq -r '.[] | select(.eolStatus and .eolStatus != "EolAllClear" and .eolStatus != "EolUnknown") |
            "\(.name) v\(.version) in \(.projectKey)/\(.environmentKey) - EOL: \(.eolStatus)"'
```

## Real-world examples

The following examples use actual data from a LaunchDarkly account to demonstrate practical SDK version analysis.

### Example API response structure

The API returns detailed information about each SDK instance. Here is a sample response showing the data structure:

```json
[
  {
    "name": "Python Server SDK",
    "version": "9.8.0",
    "type": "server",
    "projectId": "aaaaaaaaaaaaaaaaaaaaaaaa",
    "projectKey": "api-backend",
    "projectName": "API Backend",
    "environmentId": "bbbbbbbbbbbbbbbbbbbbbbbb",
    "environmentKey": "production",
    "environmentName": "Production",
    "applicationId": "api-server-prod",
    "ldLatestVersion": "9.11",
    "eolStatus": "EolPast",
    "latestReleaseUrl": "https://github.com/launchdarkly/python-server-sdk/releases/latest",
    "connectionType": "direct",
    "relayVersion": "",
    "relayEolStatus": "",
    "relayLatestVersion": "",
    "relayLatestReleaseUrl": ""
  },
  {
    "name": "React Web SDK",
    "version": "0.2.4",
    "type": "browser",
    "projectId": "cccccccccccccccccccccccc",
    "projectKey": "customer-portal",
    "projectName": "Customer Portal",
    "environmentId": "dddddddddddddddddddddddd",
    "environmentKey": "production",
    "environmentName": "Production",
    "applicationId": "react-client-sdk",
    "ldLatestVersion": "3.3",
    "eolStatus": "MajorVersionAvailable",
    "latestReleaseUrl": "https://github.com/launchdarkly/react-client-sdk/releases/latest",
    "connectionType": "direct",
    "relayVersion": "",
    "relayEolStatus": "",
    "relayLatestVersion": "",
    "relayLatestReleaseUrl": ""
  },
  {
    "name": "Node.js Server SDK",
    "version": "9.10.5",
    "type": "server",
    "projectId": "eeeeeeeeeeeeeeeeeeeeeeee",
    "projectKey": "mobile-app",
    "projectName": "Mobile Application",
    "environmentId": "ffffffffffffffffffffffff",
    "environmentKey": "production",
    "environmentName": "Production",
    "applicationId": "NodeJSClient",
    "ldLatestVersion": "9.9",
    "eolStatus": "EolAllClear",
    "latestReleaseUrl": "https://github.com/launchdarkly/js-core/releases/latest",
    "connectionType": "direct",
    "relayVersion": "",
    "relayEolStatus": "",
    "relayLatestVersion": "",
    "relayLatestReleaseUrl": ""
  }
]
```

### Analyzing relay proxy version distribution

A common scenario is identifying which relay proxy versions are deployed across your infrastructure. This example shows an organization with 41 relay proxy instances distributed across two versions:

```python
import requests
from collections import defaultdict

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

# Analyze relay proxy distribution
relay_by_version = defaultdict(list)
for sdk in sdk_versions:
    if sdk['name'] == 'LDRelay':
        relay_by_version[sdk['version']].append({
            'project': sdk['projectKey'],
            'environment': sdk['environmentKey']
        })

# Display results
print("Relay Proxy Version Distribution:")
print("=" * 60)
for version, instances in sorted(relay_by_version.items()):
    print(f"\nVersion {version}: {len(instances)} instances")
    print(f"Sample deployments:")
    for inst in instances[:5]:
        print(f"  - {inst['project']}/{inst['environment']}")
```

**Sample output:**

```
Relay Proxy Version Distribution:
============================================================

Version 8.17.3: 38 instances
Sample deployments:
  - mobile-demo/production
  - mobile-demo/test
  - stream-service/production
  - api-gateway/test
  - customer-portal/production

Version 8.17.4: 3 instances
Sample deployments:
  - core-platform/production
  - core-platform/test
  - core-platform/dev
```

**Analysis:** This output reveals that 38 relay proxy instances are running version 8.17.3, while only 3 have been upgraded to 8.17.4. This indicates a potential upgrade opportunity to standardize on the newer version.

### Identifying version drift across environments

Version drift occurs when different environments run different SDK or relay proxy versions. This can lead to inconsistent behavior and makes troubleshooting difficult.

```python
import requests
from collections import defaultdict

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

# Track versions per project
project_versions = defaultdict(lambda: defaultdict(set))
for sdk in sdk_versions:
    project_versions[sdk['projectKey']][sdk['name']].add(
        (sdk['version'], sdk['environmentKey'])
    )

# Find projects with version drift
print("Projects with version drift:")
print("=" * 60)
for project, sdks in sorted(project_versions.items()):
    for sdk_name, versions in sdks.items():
        unique_versions = set(v[0] for v in versions)
        if len(unique_versions) > 1:
            print(f"\n{project} - {sdk_name}:")
            for version in sorted(unique_versions):
                envs = [v[1] for v in versions if v[0] == version]
                print(f"  v{version}: {', '.join(envs)}")
```

**Sample output:**

```
Projects with version drift:
============================================================

mobile-demo - LDRelay:
  v8.17.3: production, test
  v8.17.4: staging

api-gateway - Node.js Server SDK:
  v9.8.1: production
  v9.10.2: test, dev
```

**Recommendation:** Standardize on a single version across environments within each project to ensure consistent behavior and simplify troubleshooting.

### SDK inventory report

Generate a comprehensive report of all SDKs in use across your organization:

```python
import requests
from collections import defaultdict

url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

response = requests.get(url, headers=headers)
sdk_versions = response.json()

# Summarize SDK usage
print("SDK Inventory Report")
print("=" * 80)
print(f"\nTotal SDK instances: {len(sdk_versions)}")
print(f"Unique projects: {len(set(s['projectKey'] for s in sdk_versions))}")
print(f"Unique environments: {len(set(s['environmentKey'] for s in sdk_versions))}")

# SDK breakdown
sdk_counts = defaultdict(set)
for sdk in sdk_versions:
    sdk_counts[sdk['name']].add(sdk['version'])

print("\nSDK Distribution:")
print("-" * 80)
for sdk_name, versions in sorted(sdk_counts.items()):
    count = sum(1 for s in sdk_versions if s['name'] == sdk_name)
    print(f"{sdk_name}:")
    print(f"  Instances: {count}")
    print(f"  Versions: {', '.join(sorted(versions))}")
    
    # Show EOL status if available
    sample = next(s for s in sdk_versions if s['name'] == sdk_name)
    if sample.get('eolStatus') and sample['eolStatus'] != 'EolUnknown':
        print(f"  EOL Status: {sample['eolStatus']}")
    print()

# Environment coverage
env_counts = defaultdict(int)
for sdk in sdk_versions:
    env_counts[sdk['environmentKey']] += 1

print("\nEnvironment Coverage:")
print("-" * 80)
for env, count in sorted(env_counts.items(), key=lambda x: -x[1]):
    print(f"{env}: {count} SDK instances")
```

**Sample output:**

```
SDK Inventory Report
================================================================================

Total SDK instances: 46
Unique projects: 17
Unique environments: 8

SDK Distribution:
--------------------------------------------------------------------------------
.NET Server SDK:
  Instances: 1
  Versions: 8.11.1
  EOL Status: EolAllClear

Go Server SDK:
  Instances: 1
  Versions: 7.14.6
  EOL Status: EolAllClear

LDRelay:
  Instances: 41
  Versions: 8.17.3, 8.17.4

Node.js Server SDK:
  Instances: 2
  Versions: 9.10.2
  EOL Status: EolAllClear

Python Server SDK:
  Instances: 1
  Versions: 9.14.1
  EOL Status: EolAllClear

Environment Coverage:
--------------------------------------------------------------------------------
production: 19 SDK instances
test: 17 SDK instances
dev: 4 SDK instances
sit: 2 SDK instances
qa: 1 SDK instances
```

**Insights from this data:**
- Relay proxy is the most deployed component (41 instances)
- Production and test environments have the highest SDK coverage
- Most server-side SDKs show healthy EOL status
- Version standardization opportunity exists for relay proxy

### Finding projects without SDK coverage

Identify projects that may not have SDK instrumentation:

```python
import requests

# Fetch all projects (requires separate API call)
projects_url = "https://app.launchdarkly.com/api/v2/projects"
sdk_url = "https://app.launchdarkly.com/api/v2/usage/sdk-versions/details"
headers = {
    "Authorization": "api-your-access-token",
    "LD-API-Version": "beta"
}

# Get all projects
projects_response = requests.get(projects_url, headers=headers)
all_projects = set(p['key'] for p in projects_response.json()['items'])

# Get projects with SDK usage
sdk_response = requests.get(sdk_url, headers=headers)
projects_with_sdks = set(s['projectKey'] for s in sdk_response.json())

# Find projects without SDK instrumentation
projects_without_sdks = all_projects - projects_with_sdks

print(f"Projects without active SDK usage: {len(projects_without_sdks)}")
for project in sorted(projects_without_sdks):
    print(f"  - {project}")
```

This helps identify projects that may need SDK implementation or where SDKs have not reported telemetry recently.

## Best practices

### Monitor regularly

Schedule regular checks of SDK versions:
- Run automated checks weekly or monthly
- Alert teams when EOL SDKs are detected
- Track upgrade progress over time

### Prioritize upgrades

Focus upgrade efforts based on risk:
1. **Critical**: SDKs past end-of-life with known security issues
2. **High**: SDKs approaching end-of-life
3. **Medium**: SDKs more than two major versions behind
4. **Low**: SDKs one minor version behind

### Document versions

Maintain documentation of SDK versions:
- Record which versions are approved for use
- Document known issues with specific versions
- Track upgrade timelines and dependencies

### Test upgrades

Test SDK upgrades thoroughly:
- Review release notes for breaking changes
- Test in non-production environments first
- Monitor error rates and performance after upgrading
- Have rollback plans ready

To learn more about SDK implementation best practices, read [Preflight Checklist](../preflight-checklist.md).
To learn more about maintaining resilient SDK implementations, read [Resilient SDK Implementation](../resilient-sdk-implementation.md).

<div class="page-metadata"><table class="page-metadata-table" aria-label="Page metadata"><thead><tr><th scope="col">Last modified</th><th scope="col">Last reviewed</th><th scope="col">Review due</th></tr></thead><tbody><tr><td><time datetime="2026-04-29">2026-04-29</time></td><td></td><td></td></tr><tr><td>Last commit: <a href="https://github.com/launchdarkly-labs/ps-flag-book/commit/2e92061">2e92061</a></td><td></td><td></td></tr></tbody></table></div>