Ask
174
@hotswap_hana ·

can i read d1 from a plain node script or does everything have to go through a worker

i have a nightly reporting script that runs on a small vm and produces a csv for the finance side. the data it needs lives in d1 and right now i've got an undocumented worker endpoint with a shared secret in a header purely so the script can get at it, which feels like a hack i'll regret. is there a supported way to query d1 from outside the workers runtime?

9 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @migration_marek · 3mo ago

    Yes — there's an HTTP API. POST to /accounts/{account_id}/d1/database/{database_id}/query with an API token in the Authorization header as a bearer token, send the sql and params in the body, and you get rows back as json.

    That's a supported endpoint, not a workaround, and it's what wrangler is using under the hood when you run wrangler d1 execute --remote. For a nightly script producing a csv it's exactly right — no worker in the path, no shared secret you invented yourself, and the credential is revocable from the dashboard.

    186
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @leaky_bucket_ed · 3mo ago · 3 replies

    Do the token scoping properly when you set this up, because the default is worse than the hack you already have.

    Create a dedicated API token restricted to D1 on the one account, not a global key, and store it wherever that vm keeps secrets rather than in the script. I once had an account-wide token echoed into a CI log by a debug line that printed the whole environment, and rotating everything that touched took a full day.

    A header secret on a worker endpoint at least only unlocks that endpoint. An account key unlocks everything.

    121
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @hotswap_hana · 3mo ago

      good catch, i'd have reached for the global key by reflex because it's the one already on the machine for something else. making a d1-scoped one today.

      39
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @migration_marek · 3mo ago

      And put an expiry on it. Reporting scripts outlive the people who wrote them and a token with no end date is how you end up with a credential nobody can account for.

      25
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @seedstart_sim · 3mo ago · 3 replies

    I'll argue for keeping a worker in front, against the room.

    The HTTP API is fine and it hands your script raw sql access to the whole database. A tiny worker that exposes exactly one report — no sql from the caller, just a date range — means a compromised vm can read one report rather than every table you own. It's twenty lines and it's the difference between an endpoint and a database connection.

    The real problem with what you have now isn't the worker, it's that the secret is homemade and probably never rotates. Fix that part and the design is defensible.

    88
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @hotswap_hana · 3mo ago

      that's a fair reframe — the thing i disliked was the homemade secret, not the worker. a single report endpoint with a scoped token and rotation is a much smaller thing to defend than raw sql from a vm.

      32
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @null_pointer_ok · 3mo ago

      Both can be true. Use the HTTP API from your laptop for ad-hoc work, keep the narrow endpoint for anything that runs unattended.

      21
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @null_pointer_ok · 3mo ago

    Practical notes from running the HTTP API nightly for about a year. It's a normal https request, so it's slower per query than a binding inside a worker — batch your statements rather than looping row by row from node, or the round trips will dominate.

    Also the response shape isn't identical to the binding's, so if you share code between a worker and a script, wrap it once. I didn't and spent an hour on a results versus result[0].results mismatch.

    67
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @retainer_rue · 3mo ago

    Supported HTTP endpoint exists, use a D1-scoped token, batch the statements. Keep a worker in front only if you want to limit what the caller can ask for.

    42
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report