Skip to content

Add Getting Started with LDK Node guide - #315

Open
Camillarhi wants to merge 2 commits into
lightningdevkit:mainfrom
Camillarhi:docs/getting-started-with-ldk-node
Open

Add Getting Started with LDK Node guide#315
Camillarhi wants to merge 2 commits into
lightningdevkit:mainfrom
Camillarhi:docs/getting-started-with-ldk-node

Conversation

@Camillarhi

@Camillarhi Camillarhi commented Jun 12, 2026

Copy link
Copy Markdown

Adds a guide for building a Lightning node with ldk-node in Rust, covering node setup, channel management, BOLT11/BOLT12 payments, and spontaneous payments against a local Polar regtest network.

Adds:

  • docs/getting-started-with-ldk-node.md
  • sidebar/config entries in docs/.vitepress/config.mts and docs/.vuepress/config.js
  • footer link in docs/.vitepress/theme/components/SiteFooter.vue

🤖 Kotlin code examples generated with Claude Code

@netlify

netlify Bot commented Jun 12, 2026

Copy link
Copy Markdown

Deploy Preview for lightningdevkit ready!

Name Link
🔨 Latest commit 80c1f3d
🔍 Latest deploy log https://app.netlify.com/projects/lightningdevkit/deploys/6a74d0b594b2800008d92b2c
😎 Deploy Preview https://deploy-preview-315--lightningdevkit.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@Camillarhi
Camillarhi force-pushed the docs/getting-started-with-ldk-node branch from 5ca6ec4 to 16a8ba1 Compare June 13, 2026 02:08

@ConorOkus ConorOkus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated code review (Claude Code) — 3 inline comments below on the guide's code samples, plus one issue that can't be anchored inline:

PR body promises a footer link that isn't in the diff. The description says "footer link in docs/.vitepress/theme/components/SiteFooter.vue", but the diff doesn't touch that file and it has no getting-started entry. The footer entry that was added lives in the legacy docs/.vuepress/config.js, which the live VitePress build doesn't read (the build workflow publishes docs/.vitepress/dist). Either add { text: 'Getting Started with LDK Node', link: '/getting-started-with-ldk-node' } to the Docs column in SiteFooter.vue, or amend the PR description.

Verdict: ready with fixes — structure, flow, and sidebar wiring are sound; the three inline items are small, localized edits to the code samples.

Comment thread docs/getting-started-with-ldk-node.md Outdated
Comment thread docs/getting-started-with-ldk-node.md Outdated
Comment thread docs/getting-started-with-ldk-node.md Outdated
@Camillarhi
Camillarhi force-pushed the docs/getting-started-with-ldk-node branch from 16a8ba1 to 004377c Compare July 24, 2026 10:31
@ConorOkus

Copy link
Copy Markdown
Contributor

One remaining issue from review, in the persistence guidance:

docs/getting-started-with-ldk-node.md line 310 recommends build_with_sqlite_store() and build_with_postgres_store(), but neither method exists on ldk-node 0.7's Builder — the available options are build() (SQLite is the default backend), build_with_fs_store(), build_with_store(), and the build_with_vss_store* variants. There's no Postgres persistence support.

Suggested rewrite for line 310:

On persistence: build_with_fs_store() persists node state to the filesystem. For production, you would likely prefer the default build() (which uses SQLite) or build_with_vss_store() depending on your storage requirements.

Line 17 repeats the claim ("State is persisted to SQLite, Postgres or the filesystem") — Postgres should be dropped there too.

Everything else from the earlier review round looks resolved in 004377c — thanks!

@Camillarhi
Camillarhi force-pushed the docs/getting-started-with-ldk-node branch from 004377c to de79bfe Compare July 24, 2026 20:36
@Camillarhi
Camillarhi requested a review from ConorOkus July 24, 2026 20:36
@Camillarhi
Camillarhi force-pushed the docs/getting-started-with-ldk-node branch 2 times, most recently from b71b3d3 to 765b70b Compare July 24, 2026 20:40
@Camillarhi

Copy link
Copy Markdown
Author

One remaining issue from review, in the persistence guidance:

docs/getting-started-with-ldk-node.md line 310 recommends build_with_sqlite_store() and build_with_postgres_store(), but neither method exists on ldk-node 0.7's Builder — the available options are build() (SQLite is the default backend), build_with_fs_store(), build_with_store(), and the build_with_vss_store* variants. There's no Postgres persistence support.

Suggested rewrite for line 310:

On persistence: build_with_fs_store() persists node state to the filesystem. For production, you would likely prefer the default build() (which uses SQLite) or build_with_vss_store() depending on your storage requirements.

Line 17 repeats the claim ("State is persisted to SQLite, Postgres or the filesystem") — Postgres should be dropped there too.

Everything else from the earlier review round looks resolved in 004377c — thanks!

Thanks. This has been updated

@ConorOkus

Copy link
Copy Markdown
Contributor

To avoid confusion, I think it's worth changing the title to "Building on mobile with LDK Node"

@Camillarhi

Copy link
Copy Markdown
Author

To avoid confusion, I think it's worth changing the title to "Building on mobile with LDK Node"

I see where you're coming from, but I'd lean away from a mobile-specific title. The article builds against a local Polar regtest setup, and the Kotlin examples use JVM with Gradle and a terminal flow, not Android. A mobile dev could adapt it, but they wouldn't get the mobile-specific setup like Android project setup or the .aar dependency. I think something like 'Getting Started with LDK Node' fits the content better, but open to other ideas.

@ConorOkus ConorOkus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — it's a genuinely useful guide and clearly the product of actually running the thing. I checked every API call in it against the ldk-node 0.7.0 rustdoc and the v0.7.0 UniFFI definitions, and the signatures, arities and units all check out in both languages. The three comments from the last round are all addressed too.

Most of what's below isn't about the API usage — it's about what the guide tells the reader. Since this is official docs, readers will copy both the code and the prose into nodes that hold real funds, so I've weighted it that way.

The things I'd most like to see before merge:

  1. set_storage_dir_path is never called, so the wallet seed and every channel monitor land in /tmp/ldk_node. That's the one with actual funds risk.
  2. The BOLT12 walkthrough can't be completed as written — no onion-message peer is ever connected, and then the flow asks the reader to pay the offer in Polar, which the page itself says Polar can't do. Worth settling the intended Polar topology once; that answers both.
  3. Two statements are factually inverted — the push-amount liquidity direction, and what actually happens when you skip event_handled().

The rest are smaller. Nothing here is a reason not to land it — happy to re-review whenever.

Comment thread docs/getting-started-with-ldk-node.md Outdated

Note: [LDK Server](https://github.com/lightningdevkit/ldk-server) is being added to Polar ([PR #1374](https://github.com/jamaljsr/polar/pull/1374)). Once merged, you will be able to use it directly as your local node backend, since LDK Server is essentially ldk-node with an RPC interface. It will also work as an onion-message-capable peer for BOLT12 offer creation.

Note: To create BOLT12 offers, your ldk-node needs to connect to an onion-message-capable peer. In Polar, this means adding a CLN node to your network. LND does not currently support onion messages, so offer creation will fail if CLN is not present.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prerequisite is correct, but nothing in the guide ever satisfies it. The code only opens a channel to Node B and never calls node.connect(...), so a reader who follows along lands in create_offer's error branch with no way forward beyond the message "make sure your node is connected."

Two ways out, depending on what your Polar setup actually looked like:

  • If Node B was the CLN node, say so here — then the channel peer is also the onion-message peer and it just works.
  • If CLN was a separate node, add the connect before create_offer:
node.connect(cln_pubkey, cln_addr, true).unwrap();
node.connect(clnPubkey, clnAddr, true)

Related to the comment on line 1247 — one decision about the topology resolves both.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prerequisite already covers this. Readers are told before any code that offers need an onion-message-capable peer, and in Polar that means a CLN node, and that it'll fail without one. And open_channel connects to the peer anyway, so if they set it up according to this guide, there's nothing extra to add.

If someone is running LND, create_offer hits the error branch rather than panicking, so it prints and carries on. I'd rather leave it like that than hardcode a CLN node into the example, since not everyone runs Polar, and LDK Server works as the peer too once PR #1374 is in.

I also kept the error wording generic on purpose. CLN won't be the only option for long, LDK Server relays onion messages as well since it's ldk-node underneath, so naming CLN in the code would just go stale. The Polar-specific bit also lives in the prerequisite.

Comment thread docs/getting-started-with-ldk-node.md Outdated
println!("Press enter to create a BOLT12 offer for Node B to pay (inbound payment)...");
std::io::stdin().read_line(&mut String::new()).unwrap();
create_offer(Arc::clone(&node));
println!("\nPay the offer from Node B in Polar, then press Enter when done...");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This contradicts the page's own note at line 778 ("Paying a BOLT12 offer end to end through Polar's UI is not currently supported"), which the screenshot caption at line 975 repeats. A reader gets here, is told to pay the offer in Polar, and can't. Same prompt in the Kotlin listing at line 1494, and in the incremental listings at 871 / 930.

Simplest fix is to end the BOLT12 receive demo at offer creation and say plainly that paying it back needs a payer outside this setup — which is what the note already says. Alternatively, drop in a CLN command-line pay flow if you've run one.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped that prompt. The receive side now ends at creating the offer, and the send step takes an offer if you have one and skips if you just hit enter.

Kept send_bolt12_payment in because Polar isn't the only way people run this. If you're driving CLN directly it works both ways, so it seemed worth showing even though Polar can't demo it.

What do you think?

Comment thread docs/getting-started-with-ldk-node.md Outdated
Comment thread docs/getting-started-with-ldk-node.md Outdated
Comment thread docs/getting-started-with-ldk-node.md Outdated
Comment thread docs/getting-started-with-ldk-node.md
Comment thread docs/getting-started-with-ldk-node.md
Comment thread docs/getting-started-with-ldk-node.md Outdated
children: [
{ text: 'Introduction', link: '/introduction/' },
{ text: 'Building a node with LDK', link: '/building-a-node-with-ldk/introduction/' },
{ text: 'Getting Started with LDK Node', link: '/getting-started-with-ldk-node/' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, and honestly pre-existing rather than yours: the trailing slash makes this 404.

https://lightningdevkit.org/running-a-sample-ldk-node/  -> 404
https://lightningdevkit.org/running-a-sample-ldk-node   -> 200

Every entry in this footer list has the same trailing slash, so it's a site-wide thing, not something this PR introduced — but this adds one more instance. Your sidebar entry in config.mts uses the correct bare form already. Note ignoreDeadLinks: true means the build won't flag it.

Happy for this to be out of scope; just flagging since you're touching the file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the pre-existing as a separate commit

Walkthrough for building a Lightning node with ldk-node in Rust and kotlin
covering node setup, channel management, BOLT11 and BOLT12 payments, and
spontaneous payments using Polar for a local regtest environment.
@Camillarhi
Camillarhi force-pushed the docs/getting-started-with-ldk-node branch from 765b70b to 80c1f3d Compare August 6, 2026 18:21
@Camillarhi
Camillarhi requested a review from ConorOkus August 6, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants