Skip to content

Instantly share code, notes, and snippets.

@shawnyeager
Created November 27, 2025 22:27
Show Gist options
  • Select an option

  • Save shawnyeager/a0cb021fd620d98bfa2e46fdc90aa5f2 to your computer and use it in GitHub Desktop.

Select an option

Save shawnyeager/a0cb021fd620d98bfa2e46fdc90aa5f2 to your computer and use it in GitHub Desktop.
Faster Lightning Address Payments with Netlify Edge Functions

Faster Lightning Address Payments with Netlify Edge Functions

Problem: Using HTTP redirects for Lightning Address (sats@example.comuser@getalby.com) adds 200-500ms latency because wallets must follow the redirect before fetching the LNURL-pay response.

Solution: Replace redirects with an Edge Function proxy that fetches from Alby server-side and returns the response directly.

How it works

Before (redirect):
Wallet → example.com → 302 redirect → Wallet → getalby.com → response

After (proxy):
Wallet → example.com → [edge fetches getalby.com] → response

The wallet makes one request. The server-to-server fetch happens on fast edge networks (even faster than regular serverless functions).

Why Edge Functions?

  • Lower latency: Run at the edge, closer to users (~10-50ms vs ~50-100ms for serverless)
  • Simpler setup: No build step, TypeScript runs directly
  • Free tier: 3 million invocations/month (vs 125k for serverless functions)

Implementation

1. Create netlify/edge-functions/lnurlp.ts

import type { Context, Config } from "@netlify/edge-functions";

export default async (req: Request, context: Context) => {
  const url = new URL(req.url);
  const pathParts = url.pathname.split('/');
  const username = pathParts[pathParts.length - 1];

  // All aliases map to the same Alby account
  const validUsernames = ['sats', 'user', 'zap'];
  if (!validUsernames.includes(username)) {
    return new Response(JSON.stringify({
      status: "ERROR",
      reason: "User not found"
    }), {
      status: 404,
      headers: { "Content-Type": "application/json" }
    });
  }

  // Fetch from Alby
  const albyResponse = await fetch(
    "https://getalby.com/.well-known/lnurlp/YOUR_ALBY_USERNAME"
  );

  if (!albyResponse.ok) {
    return new Response(JSON.stringify({
      status: "ERROR",
      reason: "Upstream error"
    }), {
      status: 502,
      headers: { "Content-Type": "application/json" }
    });
  }

  const data = await albyResponse.json();

  // Rewrite metadata to show vanity address instead of Alby address
  if (data.metadata) {
    data.metadata = data.metadata.replace(
      'YOUR_ALBY_USERNAME@getalby.com',
      `${username}@example.com`
    );
  }

  return new Response(JSON.stringify(data), {
    status: 200,
    headers: {
      "Content-Type": "application/json",
      "Cache-Control": "no-store"
    }
  });
};

export const config: Config = {
  path: "/.well-known/lnurlp/*"
};

2. Install types (optional, for IDE support)

npm install --save-dev @netlify/edge-functions

3. Remove old redirects

If you had redirects in _redirects or netlify.toml for /.well-known/lnurlp/*, remove them. Edge Functions take precedence, but cleaner to remove.

Customization

  • validUsernames: Array of aliases that map to your Alby account (e.g., sats, user, zap)
  • Alby URL: Replace YOUR_ALBY_USERNAME with your actual Alby username
  • Metadata rewrite: The text/identifier in Alby's response tells wallets the recipient address. Without rewriting it, wallets display you@getalby.com instead of your vanity address.

Result

  • Vanity address preserved (sats@example.com)
  • Single HTTP request from wallet perspective
  • Edge-to-origin fetch is fast (~10-50ms)
  • Free tier: 3 million edge function invocations/month

Testing

# Local
netlify dev
curl http://localhost:8888/.well-known/lnurlp/sats

# Should return JSON with "status": "OK", not a redirect

Latency Comparison

Tested from US East, November 2025:

Method Avg Latency Requests Vanity Address
Direct to Alby ~80ms 1 No
Edge Proxy ~220ms 1 Yes
302 Redirect ~305ms 2 No

The edge proxy is ~85ms faster than redirects. Redirects require two round-trips from the wallet (302 response + Alby fetch), while the proxy handles the Alby fetch server-side on fast edge networks.

Bonus: The proxy rewrites metadata so wallets display your vanity address (sats@example.com) instead of the upstream provider (user@getalby.com).

How Lightning Address works

  1. Wallet parses sats@example.com → queries https://example.com/.well-known/lnurlp/sats
  2. Server returns LNURL-pay JSON with callback URL, min/max amounts, metadata
  3. Wallet requests invoice from callback URL
  4. Payment executes

The proxy intercepts step 2, fetching from Alby and returning the response as if it originated from your domain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment