Skip to content

Migration Helpers

Shadowfen edited this page Jul 29, 2026 · 3 revisions

Migration helpers are utility functions that simplify common saved variable migration tasks. They are designed to reduce repetitive table manipulation code and make migrations easier to read, maintain, and test.

While a custom migration function can perform any transformation required, migration helpers provide a safer and more consistent way to handle common operations such as:

  • Moving settings.
  • Copying settings.
  • Removing obsolete settings.
  • Creating missing table paths.
  • Migrating between account-wide and character storage.

Migration helpers are typically used inside a version migration callback.

Example:

settings:Migrate(2, function(savedVars)

    -- migration helper operations

end)

Why Use Migration Helpers?

Without helpers, migrations often contain repeated code:

settings:Migrate(2, function(savedVars)

    if savedVars.oldSetting ~= nil then
        savedVars.newSetting = savedVars.oldSetting
        savedVars.oldSetting = nil
    end

end)

This approach works, but every migration must manually handle:

  • Missing values.
  • Existing destination values.
  • Nested table creation.
  • Removing obsolete data.
  • Avoiding accidental overwrites.

Migration helpers centralize these behaviors and make the intent of the migration clearer.


Path Operations

Many migrations involve moving data between different locations in the saved variable table.

For example, changing from:

settings.scale

to:

settings.ui.scale

requires creating the ui table before moving the value.

Migration helpers handle these path operations automatically.


Creating Missing Paths

When moving data into a new location, intermediate tables may not exist.

Example:

Before:

{
    scale = 1.0
}

After:

{
    ui = {
        scale = 1.0
    }
}

A path creation helper ensures that the destination exists before storing the value.

Conceptually:

CreatePath(
    savedVars,
    "ui"
)

creates:

savedVars.ui = {}

when required.


Moving Settings

A move operation transfers a value from one location to another.

A move:

  1. Copies the value to the destination.
  2. Removes the original value.
  3. Preserves the user's setting.

Example:

Version 1:

{
    opacity = 0.8
}

Version 2:

{
    ui = {
        opacity = 0.8
    }
}

Migration:

settings:Migrate(2, function(savedVars)

    Move(
        savedVars,
        "opacity",
        "ui.opacity"
    )

end)

After migration:

{
    ui = {
        opacity = 0.8
    }
}

Move helpers are commonly used for:

  • Renaming settings.
  • Reorganizing tables.
  • Consolidating configuration sections.

Copying Settings

A copy operation creates a new value while preserving the original.

This is useful when adding a new setting while keeping the old data available.

Example:

Before:

{
    color = "red"
}

After:

{
    color = "red",
    primaryColor = "red"
}

Migration:

settings:Migrate(2, function(savedVars)

    Copy(
        savedVars,
        "color",
        "primaryColor"
    )

end)

Use copying when:

  • The old setting may still be required.
  • Multiple systems need the same value.
  • A gradual transition is desired.

Removing Settings

Old settings that are no longer used can be removed during migration.

Example:

Before:

{
    enabled = true,
    debugMode = false
}

Migration:

settings:Migrate(3, function(savedVars)

    Remove(
        savedVars,
        "debugMode"
    )

end)

After:

{
    enabled = true
}

Removing unused settings keeps SavedVariables files clean and prevents obsolete data from accumulating.


Nested Table Operations

Migration helpers should support nested paths when working with complex settings.

Example:

Move:

settings.display.position.x

to:

settings.ui.location.x

Conceptually:

Move(
    savedVars,
    "display.position.x",
    "ui.location.x"
)

The helper handles:

  • Creating missing tables.
  • Reading the existing value.
  • Removing the old path.

Account-Wide and Character Migration Helpers

LibSavedVars supports migrating data between different storage models.

Common scenarios include:

Account-Wide to Character

Example:

Version 1:

Account-wide
└── build = "Tank"

Version 2:

Character
├── Character A
│   └── build = "Tank"
└── Character B
    └── build = "Tank"

The migration copies the account-wide value into the character storage.


Character to Account-Wide

Example:

Version 1:

Character
├── Character A
│   └── theme = "Dark"
├── Character B
│   └── theme = "Dark"

Version 2:

Account-wide
└── theme = "Dark"

The migration consolidates the character values into shared storage.


Helper Behavior

Good migration helpers should follow these principles.

Safe Execution

A migration should handle missing data gracefully.

Example:

Move(
    savedVars,
    "oldSetting",
    "newSetting"
)

should do nothing if oldSetting no longer exists.


Avoid Data Loss

Helpers should avoid overwriting existing values unless explicitly requested.

Example:

savedVars.newSetting = savedVars.oldSetting

could overwrite a user's existing value.

A safer approach:

if savedVars.newSetting == nil then
    savedVars.newSetting = savedVars.oldSetting
end

Version Controlled

Migration helpers do not determine when they run.

The version system controls execution:

settings:Migrate(4, function(savedVars)

    Move(
        savedVars,
        "oldName",
        "newName"
    )

end)

The version answers:

"Should this migration run?"

The helper answers:

"How should the data change?"


When Not to Use Migration Helpers

A custom migration callback is better when the transformation requires logic.

Examples:

  • Combining multiple settings.
  • Calculating new values.
  • Validating data.
  • Converting formats.

Example:

settings:Migrate(5, function(savedVars)

    savedVars.position = {
        x = savedVars.oldX * 2,
        y = savedVars.oldY * 2,
    }

end)

A helper would not make this clearer.


Best Practices

When using migration helpers:

  • Keep each migration tied to one version.
  • Use helpers for simple, predictable transformations.
  • Use custom callbacks for complex conversions.
  • Remove obsolete settings after migration.
  • Test migrations using older SavedVariables data.
  • Never modify released migrations after users have received them.

Summary

Migration helpers provide reusable building blocks for maintaining saved variable compatibility across addon versions.

Use them for:

Task Recommended Helper
Rename a setting Move
Move data into a new table CreatePath + Move
Duplicate a setting Copy
Delete obsolete data Remove
Change storage location Account/Character migration helpers
Complex transformation Custom migration callback

Together with versioning, migration helpers allow LibSavedVars-based addons to evolve safely while preserving user settings.

Clone this wiki locally