Skip to content

Migration Helpers

Shadowfen edited this page Jul 29, 2026 · 3 revisions

In LibSavedVars, migration helpers are convenience functions that simplify common saved-variable transformations. They are intended for cases where a normal Migrate(version, callback) function would require repetitive or error-prone table manipulation.

A migration helper usually performs a specific, well-defined operation such as:

  • Creating a missing path.

  • Moving a value from one location to another.

  • Copying data between locations.

  • Removing obsolete settings.

  • Moving data between character and account-wide storage.

They are especially useful when an addon has been released for a while and its saved variable structure has changed several times.

Why Use Migration Helpers?

Without helpers, a migration often looks like this:

settings:Migrate(2, function(savedVars)
savedVars.ui = savedVars.ui or {}

savedVars.ui.scale = savedVars.scale
savedVars.scale = nil

end)

This works, but every migration author has to correctly handle:

  • Missing intermediate tables.

  • Nil values.

  • Existing destination values.

  • Removing old data.

  • Avoiding accidental overwrites.

A helper can encapsulate these rules:

settings:Migrate(2, function(savedVars)
protected.MovePath(
    savedVars,
    {"scale"},
    {"ui", "scale"}
)

end)

The migration becomes clearer: move scale into ui.scale.


Common Migration Helper Categories

Path Creation Helpers

Many migrations need to create a table hierarchy before assigning a value.

Example:

Before:

{
enabled = true
}

After:

{
general = {
enabled = true
}
}

A helper can create the missing path:

CreatePath(savedVars, "general")

instead of requiring:

savedVars.general = savedVars.general or {}

at every step.


Move Helpers

A move operation copies a value to a new location and removes the old value.

Example:

Version 1:

settings.opacity

Version 2:

settings.ui.opacity

Migration:

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

Result:

Before:

{
opacity = 0.8
}

After:

{
ui = {
opacity = 0.8
}
}

Move helpers are useful for:

  • Renaming settings.

  • Reorganizing configuration tables.

  • Consolidating settings.


Copy Helpers

Sometimes you want to preserve the old value while creating a new one.

Example:

Version 1:

settings.color

Version 2 adds:

settings.primaryColor

A copy migration:

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

Result:

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

This is useful when the old value may still be needed for compatibility.


Remove Helpers

Old settings can accumulate over multiple releases.

Example:

{
enabled = true,
oldDebug = false
}

If oldDebug is no longer used:

Remove(
savedVars,
"oldDebug"
)

Result:

{
enabled = true
}

Removing obsolete values keeps SavedVariables clean.


Account-wide / Character Migration Helpers

One of the more advanced uses of LibSavedVars is changing where data is stored.

For example, an addon may originally use account-wide settings:

Account
└── Settings
└── scale = 1.0

Later, the addon adds per-character settings:

Account
├── Character A
│   └── scale = 1.0
└── Character B
└── scale = 1.2

A migration helper can move the existing account value into the character storage when the user changes modes.

The reverse is also possible:

Character Settings → Account Settings

This avoids forcing users to manually recreate their configuration.


Helper Design Principles

Good migration helpers should:

Be Repeatable

A migration should be safe if the source value does not exist.

Example:

Move("oldName", "newName")

should do nothing if oldName is already gone.


Avoid Data Loss

A helper should generally avoid overwriting existing data unless explicitly requested.

Example:

savedVars.newValue = savedVars.oldValue

could destroy a user's existing newValue.

A safer helper can check:

if savedVars.newValue == nil then
savedVars.newValue = savedVars.oldValue
end

Be Version-Specific

Helpers do not replace versioning.

The pattern remains:

settings:Migrate(3, function(savedVars)
Move(
    savedVars,
    "oldSetting",
    "newSetting"
)

end)

The version determines when the helper runs.
The helper determines what changes.


When Not to Use Helpers

A custom migration function is usually better when:

  • The transformation is complex.

  • Several values must be calculated together.

  • Data formats change significantly.

  • Validation is required.

Example:

settings:Migrate(5, function(savedVars)
savedVars.position = {
    x = savedVars.oldX * 2,
    y = savedVars.oldY * 2,
}

end)

A helper would not make this clearer.


Summary

Migration helpers are building blocks for common saved-variable changes. They reduce boilerplate and make migrations easier to read and maintain.

Use them for:

Task Recommended Approach
Rename a setting Move helper
Move a setting into a new table Move + CreatePath
Duplicate a setting Copy helper
Delete old data Remove helper
Change storage model Account/Character migration helper
Complex conversion Custom migration callback

For small addons, Migrate() with a custom callback is usually enough. For larger addons with many releases, migration helpers provide a safer and more maintainable upgrade path.

Clone this wiki locally