lnd/docs/db_migration_guide.md
saubyk 9a260ee0a3
docs: update db migration guide subsystem readiness for v0.21
Mark the payments relational backend as available in v0.21 and refresh
the related guidance that previously told payment-heavy operators to wait
for the v0.21 release. Add btcwallet and channel state as in-progress
subsystems targeted for v0.22 (replacing the forwarding history entry),
and update the migration flow diagram and future improvements list to
match.
2026-05-26 18:34:17 -07:00

9.9 KiB

LND Database Upgrade Guide: A Two-Stage Migration for Node Operators

Table of Contents


Overview

The LND Database Upgrade process enables node operators to migrate from the legacy bbolt key-value store to modern SQLite or PostgreSQL backends—first in kvdb mode, then ultimately to a relational database format. This two-stage migration addresses long-standing performance bottlenecks, and lays the foundation for scalable, maintainable node operations.

This guide explains the migration path, backend trade-offs, subsystem readiness, and best practices for safely upgrading your LND database.


Operation Modes

The LND database upgrade operates in two sequential stages, each with distinct tooling and implications:

flowchart TD
    %% 1. Define all nodes
    Bbolt["Bbolt (kvdb)"]
    SQLite["SQLite (kvdb)"]
    Postgres["Postgres (kvdb)"]
    
    M1_Sqlite["Migration #1 (lnd v0.19)<br>Invoices"]
    M2_Sqlite["Migration #2 (lnd v0.20)<br>Graph"]
    M3_Sqlite["Migration #3 (lnd v0.21)<br>Payments"]
    M4_Sqlite["Migration #4 (lnd v0.22)<br>Btcwallet & Channel State"]

    M1_Postgres["Migration #1 (lnd v0.19)<br>Invoices"]
    M2_Postgres["Migration #2 (lnd v0.20)<br>Graph"]
    M3_Postgres["Migration #3 (lnd v0.21)<br>Payments"]
    M4_Postgres["Migration #4 (lnd v0.22)<br>Btcwallet & Channel State"]

    %% 2. Define all links (within and between graphs)
    Bbolt --> SQLite
    Bbolt --> Postgres
    
    SQLite --> M1_Sqlite
    M1_Sqlite --> M2_Sqlite
    M2_Sqlite --> M3_Sqlite
    M3_Sqlite --> M4_Sqlite

    Postgres --> M1_Postgres
    M1_Postgres --> M2_Postgres
    M2_Postgres --> M3_Postgres
    M3_Postgres --> M4_Postgres

    %% 3. Group nodes into subgraphs
    subgraph "Step 1: Migration via lndinit"
        Bbolt
        SQLite
        Postgres
    end

    subgraph "Step 2: Migration within lnd"
        M1_Sqlite
        M2_Sqlite
        M3_Sqlite
        M4_Sqlite
        M1_Postgres
        M2_Postgres
        M3_Postgres
        M4_Postgres
    end

    %% 4. Apply Styles
    %% Define classes with explicit dark text color (#333)
    classDef bboltNode fill:#e2e3e5,stroke:#383d41,color:#333
    classDef sqliteNode fill:#d4edda,stroke:#155724,color:#333
    classDef postgresNode fill:#cce5ff,stroke:#004085,color:#333

    %% Apply classes to nodes
    class Bbolt bboltNode
    class SQLite,M1_Sqlite,M2_Sqlite,M3_Sqlite,M4_Sqlite sqliteNode
    class Postgres,M1_Postgres,M2_Postgres,M3_Postgres,M4_Postgres postgresNode
  • Stage 1: Migrate from bbolt to a SQL-based kvdb backend using the lndinit tool.
  • Stage 2: Incrementally migrate subsystem data (invoices, graph, payments, etc.) from kvdb to SQL native relational tables as support becomes available.

Stage 1: Migration from bbolt to SQLite/Postgres (kvdb)

LND cannot run with mixed backends, so all users must first leave bbolt behind. This stage uses the lndinit utility to perform an offline migration.

Choosing Your Target Backend

Backend Performance (in kvdb mode) Default in LND? Long-Term Viability
Postgres Mediocre No
SQLite Good Yes (future)

💡 Recommendation: Unless you require Postgres for infrastructure reasons, migrate to SQLite kvdb as your backend.

Postgres kvdb Migration

A migration script is available via lndinit:

  • Postgres migration script
  • Caveat: Users report degraded performance in kvdb mode. Only proceed if you plan to immediately follow with Stage 2 to migrate the available data stores to relational DB. This will mitigate the poor Postgres performance on kvdb.

SQLite kvdb Migration


Stage 2: Migration from kvdb to Relational Database

This stage unlocks true SQL performance by restructuring data into relational tables. Migration is per-subsystem and incremental.

The migration steps are automatically applied when LND is restarted after step 1 was successfully completed and the config value db.use-native-sql=true is set. You will see log lines from the SQLD subsystem about the migration, such as Starting migration of invoices from KV to SQL.

Subsystem Readiness

Subsystem Relational Backend Migration Script Status
Invoices Available Available with v0.19
Graph Available Available with v0.20
Payments Available Available with v0.21
Btcwallet 🚧 In Progress Planned Targeted with v0.22
Channel State 🚧 In Progress Planned Targeted with v0.22

Known Limitations and Edge Cases

  • Single database engine required: LND requires a single consistent backend. You cannot run invoices in relational mode while graph remain in kvdb unless both are on the same SQL engine (e.g., SQLite).
  • Data loss risk: Always back up your data/ directory before migration.
  • Downtime required: Stage 1 requires LND to be offline. Stage 2 is done at startup, requiring a LND restart.
  • Postgres kvdb performance: Postgres performance on kvdb is sub-optimal. It is recommended to make the stage 2 migration immediately to avoid performance bottlenecks. Certain RPCs like listpayments may not perform well on Postgres if the node has a lot of payments data. As of v0.21, the payments relational backend is available, so payment-heavy nodes can migrate payments to relational mode to restore good listpayments performance.
  • No migration path between SQL backend: Once migrated to either Postgres or SQLite, it is not possible to switch to the other, so choose your target backend carefully.

Best Practices for Node Operators

Choosing the Right Path

  • For most users: Choose SQLite, then migrate. Later, adopt relational backends subsystem-by-subsystem.
  • Enterprise/Postgres users: With the payments relational backend available as of v0.21, you can now perform Stage 1 + Stage 2 in quick succession.

Timing Your Migration

  • Perform migrations during low-activity periods.
  • Monitor LND release notes for relational DB support of different subsystems.

Validation

  1. Stop LND.
  2. Run migration with lndinit.
  3. Start LND with new backend flags, to execute stage 2 migrations.
  4. Validate node health: channels, balance, invoice/payment history.

Implementation Examples

Migrating to SQLite kvdb

# Stop LND
lnd --shutdown

# Backup
cp -r ~/.lnd ~/lnd-backup-$(date +%Y%m%d)

# Run migration (e.g. sqlite)
lndinit --debuglevel info migrate-db \
--source.bolt.data-dir ~/.lnd/data \
--dest.backend sqlite \
--dest.sqlite.data-dir ~/.lnd/data --network mainnet

# Start LND with SQLite backend
lnd --db.backend=sqlite

📝 Add db.backend=sqlite to your lnd.conf to make it persistent.

Migrating Invoices to Relational Backend

Once on LND v0.19+ with SQLite/Postgres:

# Ensure backend is set
echo "db.backend=sqlite" >> ~/.lnd/lnd.conf

# Start LND — invoice migration runs automatically
lnd

Check logs for:

Migrating invoices from kvdb to relational format...
Invoice migration completed successfully.

Future Improvements

The LND team is actively working on:

  • Btcwallet relational backend and migration tooling (Stage 2)
  • Channel state relational backend and migration tooling (Stage 2)
  • Automatic detection of migration readiness in lnd

Node operators should monitor:


Conclusion

The LND database upgrade is a strategic two-stage process designed to eliminate bbolt performance limitations while ensuring data integrity and operational continuity.

By first migrating to SQLite/Postgres kvdb and then adopting relational backends incrementally, node operators can achieve significant performance gains—especially for payment-heavy workloads—without rushing into unstable configurations.

Choose your path wisely, back up rigorously, and stay informed. The future of LND is relational, and this guide ensures you get there safely.