Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
D1 — Serverless SQL  ›  Lesson

D1 — A SQL Database Your Worker Can Call

D1 12 minD1 is a serverless SQLite database reached through a binding, where every query is prepared with placeholders, bound to values and run with first, all or run.

D1 — A SQL Database Your Worker Can Call

Hoplink's owners now ask real questions: "Which of my links got the most clicks last week?" "Show every link I created, newest first." KV can only fetch a value by its key; it cannot sort, filter or join. For questions like these you want SQL, and on Cloudflare that means D1, a serverless database built on SQLite.

The rule

Prepare the SQL, bind the values, pick how many rows you want.

You create a database with wrangler d1 create hop-db, add the printed d1_databases entry to your config with "binding": "DB", and every query follows the same three moves:

// 1. prepare  2. bind  3. run it and choose the shape of the result
const link = await env.DB
  .prepare("SELECT code, url, owner FROM links WHERE code = ?")
  .bind("cat")
  .first();            // one row as an object, or null

const { results } = await env.DB
  .prepare("SELECT code, url FROM links WHERE owner = ? ORDER BY created_at DESC")
  .bind("priya")
  .all();              // every matching row, in results

await env.DB
  .prepare("INSERT INTO links (code, url, owner) VALUES (?, ?, ?)")
  .bind("dog", "https://example.com/dogs", "priya")
  .run();              // for writes: returns success and meta, no rows
  • prepare takes SQL with ? placeholders — SQLite's dialect, so the SQLite functions and types apply.
  • bind fills the placeholders in order. The values travel separately from the SQL text, so a malicious code like x'; DROP TABLE links; -- is treated as plain data. This is your protection against SQL injection.
  • first / all / run choose the result shape: one row, many rows, or just "did it work".

Every result also carries meta, including how many rows were read and written — useful for understanding cost, since D1 bills by rows read and written.

D1 is strongly consistent: a row you insert is there for the very next query, unlike a KV write that spreads slowly. Each database has a primary copy in one location, so D1 fits data your app owns and queries, while KV remains the faster choice for simple global lookups.

The shortcut

Before writing a D1 call, say the question out loud and listen for the word that picks the method: "the" link → first(), "all" or "every" link → all(), "save/change/remove" → run().

Showing Priya's newest five linksStep 1 of 4
  1. Say the question

    "Get every link Priya owns, newest first, top five." The word "every" means all().

Trap: building SQL with template strings such as `WHERE code = '${code}'`. It works in testing and opens the door to SQL injection in production.

Drills

Answer fast — trust the rule.

quick drill

Which method returns a single row as an object, or null if nothing matches?

quick drill

Why use .bind(code) instead of inserting code into the SQL string?

quick drill

Which SQL dialect does D1 speak?

quick drill

You insert a new link and immediately select it. What happens?

Remember

  • Prepare the SQL, bind the values, pick how many rows you want.
  • Shortcut: "the" → first(), "every" → all(), change → run().
  • Trap: pasting values into SQL strings instead of binding them.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainA safe lookup

Write the D1 call that finds the single link with a given code, and explain why each part (prepare, bind, first) is there and why string-building the SQL is dangerous.