Deep Dive

The Lightning implementations, and how they differ

LND, Core Lightning, Eclair and LDK all speak the same wire protocol because the BOLTs say what goes on the wire and nothing about how a node is built. Everything above that line is where they diverge.

7 min readImplementations
The Lightning implementations, and how they differ

What makes them interoperable at all

Four codebases in four languages route Lightning payments to each other every day, and the reason is narrow: the BOLT specifications define the bytes on the wire and say nothing about the program that emits them. BOLT 1 fixes the message framing, BOLT 2 the channel state machine, BOLT 3 the transaction and script formats, BOLT 4 the onion, BOLT 7 gossip, BOLT 8 the encrypted transport, BOLT 11 invoices. Everything above that line, the database, the interface, the way routes get chosen, is left open.

Each project says so in its own words. LND "fully conforms to the Lightning Network specification (BOLTs)". Core Lightning is "a specification compliant Lightning Network implementation in C". Eclair "follows the Lightning Network Specifications (BOLTs)". LDK "implements all of the BOLT specifications". The document itself is careful about its status: BOLT 0 opens by calling the set "version 0", still being drafted.

So interoperability is a property of the protocol, not a favour the projects do each other.

LND

Written in Go, and the licence carries the copyright of "Lightning Labs and The Lightning Network Developers"; the official Docker images ship under lightninglabs/lnd. It is described in its own README as "a complete implementation of a Lightning Network node", and still labelled beta software.

It optimises for being built on. The README is explicit: "The daemon has been designed to be as developer friendly as possible in order to facilitate application development on top of lnd. Two primary RPC interfaces are exported: an HTTP REST API, and a gRPC service." That choice shows up everywhere downstream, in the routing services, the exchange integrations and the phone wallets that drive an LND node rather than implement Lightning themselves. It also means LND's own behaviour is load-bearing for a lot of other software, which is why a change to how it bounds what one peer can make it buffer was worth covering as news.

It also ships several pluggable chain backends rather than assuming one: bitcoind, the Go full node btcd, and Neutrino, which its own README still calls "a new experimental light client".

Core Lightning

Written in C, "developed and maintained by Blockstream", in production on mainnet since early 2018 with the launch of the Blockstream Store. The daemon is lightningd, the client lightning-cli, and the interface is "a JSON-RPC 2.0 interface over a Unix Domain socket".

It optimises for being extended, to the point where the daemon is a small core and much of what you think of as the node is a plugin. Look in the repository's plugins directory and you find not only conveniences but bcli, the Bitcoin backend itself, offers, keysend and askrene, the route-finding oracle. The plugin contract is deliberately language-neutral: "A plugin may be written in any language, and communicates with lightningd through the plugin's stdin and stdout. JSON-RPCv2 is used as protocol on top of the two streams." Plugins register their own command line options and their own JSON-RPC commands, subscribe to event streams, and use hooks to alter the daemon's behaviour.

Eclair

Written in Scala, on the JVM, by ACINQ, and French for lightning. It targets Java 21, and requires a synchronised, segwit-ready, zeromq-enabled, wallet-enabled, non-pruning, transaction-indexing Bitcoin Core node. It has no on-chain wallet of its own: "channel opening transactions are funded by your Bitcoin Core node, and channel closing transactions return funds to your Bitcoin Core node."

It optimises for running a large routing node under load. The architecture document says the reason plainly: it leans on the actor model, so that almost every entity is a separate sandboxed actor. Each peer connection is one, each channel is one, each payment attempt is one, which is how the node isolates faults and scales across CPUs. It goes further than the others in that direction with a cluster mode that splits one logical node across servers: stateless front servers absorb the gossip and sync traffic (BOLT 1 and BOLT 7), while a single backend handles channel management (BOLT 2). The interface is an HTTP JSON API, disabled by default and password-protected when enabled, and plugins are JVM jars implementing a Plugin interface.

LDK, which is not a node

LDK is the exception, and the reason it belongs in this list is that a lot of software you have used is running it. It is a Rust library. Its README states the limit up front: "Note that LDK isn't, in itself, a node."

What that means practically is that LDK deliberately does not provide the things a daemon would decide for you. On-disk storage, blockchain data, UTXO management, networking and private keys are all left to the embedding application, each behind an interface. The core lightning crate is runtime-agnostic and supports no_std. The project's own framing: "if you want to integrate Lightning with custom features such as your own chain sync, key management, data storage/backup logic, etc., LDK is likely your best option."

That is why LDK shows up inside wallets and payment platforms rather than as a process on a server. Its site lists Lightspark, Alby Hub, Cash App and Lexe as projects built on it. ACINQ does something similar with a separate codebase: Eclair is what it points routing node operators at, while Phoenix, its phone wallet, is built on lightning-kmp, a Kotlin implementation for mobile.

Where they legitimately differ

LNDCore LightningEclairLDK
LanguageGoCScalaRust
MaintainerLightning LabsBlockstreamACINQLDK developers
Shapedaemondaemondaemonlibrary
InterfacegRPC and RESTJSON-RPC over a Unix socketHTTP JSON APIRust API, plus bindings
ExtensionRPC subserversplugins in any languageJVM pluginsyour own code

Database backends. LND stores state in an embedded bbolt database by default and can be configured onto Postgres, SQLite, or etcd, and the etcd option exists to support leader election across a cluster where only one instance may write. Core Lightning takes a data source name, sqlite3:// or postgres://. Eclair defaults to SQLite and supports PostgreSQL 10.6 and above. LDK has no opinion, because persistence is the caller's job.

Watchtowers. LND ships one as a subsystem: a private altruist watchtower, plus a client that backs up encrypted justice transactions to other towers, with the caveat in its own docs that it currently covers the to_local and to_remote outputs of revoked commitments and not HTLC outputs. Core Lightning does it through the plugin interface instead, exposing a commitment_revocation hook that hands penalty transactions to a watchtower service of your choosing.

Routing heuristics. This is where two nodes given the same graph disagree, because the graph never says which side of a channel the money is on. LND keeps a subsystem called mission control, described in its source as state that "acts as a shared memory during routing attempts", tracking the time of the last failure per node and channel and turning it into a success probability fed back into path finding. Its default penalty half-life is one hour: a channel that failed is back to a 50% probability estimate after that. Core Lightning's route finding lives in the askrene plugin, which combines what it knows into "layers" you can ask questions with or without. The differences are visible as different fees and different failure rates on the same payment.

What none of this means

It is not a security ranking. The BOLTs bind all four to the same commitment transactions and the same penalty mechanism, so the guarantee you are relying on is the protocol's, not the codebase's. Choose on operational fit, on the interface you have to program against, and on whose release notes you are willing to read.

None of them removes the requirement to be online. A node that is offline when a counterparty broadcasts a revoked state cannot respond within the window, which is why watchtowers exist at all. That is a property of the protocol, not of the implementation, and it is the sharpest difference between Lightning and running a base layer node, which can be offline for a month and catch up.

Implementation choice is not invisible, either. It decides your backup procedure and your migration path, and those are the parts that lose money. LND's static channel backup is an LND mechanism, not a network one, and its safety guide says restoring from one "is not a migration but an emergency procedure". A node's channels do not move house because you changed your mind about the software. Which one is under your wallet matters less than whether you have made a payment and a backup work.

Sources

Newsletter

Bitcoin, without the noise

What happened in Bitcoin, what it actually changes, and the sources so you can check us. One issue at a time, straight to your inbox.

  • One email per issue, never a drip campaign
  • No tracking pixels and no shared addresses
  • Unsubscribe from any issue in one click

Get the next issue

One email per issue, no tracking pixels, and unsubscribe from any of them. We do not share your address. Privacy policy