Product Docs Pricing Changelog
Start free Sign in
Docs / SDK reference / Database

Database

Server-only. flarelink.from(table) returns a chainable that resolves on await. It needs the service key, so it only works where the key is safe (your server) — never the browser. Every result has the same shape:

{ rows: T[], meta: { duration, rows_read?, rows_written?, last_row_id?, changes? }, }

Query builder

// SELECT — * is the default, .select() narrows const { rows: users } = await flarelink .from<User>("users") .select(["id", "email", "active"]) .where({ active: true }) // equality + AND, NULL → IS NULL .orderBy("created_at", "desc") .limit(20) .offset(40) // INSERT (single, multi, with RETURNING) await flarelink.from("users").insert({ email: "[email protected]", name: "A" }) const { rows: created } = await flarelink .from<User>("users") .insert([{ email: "[email protected]" }, { email: "[email protected]" }]) .returning("*") // UPDATE await flarelink.from("users").update({ active: false }).where({ id: 42 }) // DELETE await flarelink.from("users").delete().where({ id: 99 })

The builder is immutable — each method returns a fresh object, so it's safe to compose partial queries and branch off them. Awaiting is the terminal step that fires the request.

Raw SQL escape hatch

For IN (…), ranges (> / < / LIKE), OR, joins, transactions — use the tagged template. Interpolated values become bind params; there's no way for a value to inject SQL.

const { rows: top } = await flarelink.sql<{ email: string; n: number }>` SELECT email, count(*) AS n FROM events WHERE created_at > ${cutoff} GROUP BY email ORDER BY n DESC LIMIT 10 `

A flarelink.sql\`…\` call runs as a single D1 batch, so a multi-statement template (BEGIN; …; COMMIT;) is atomic. The values you interpolate are coerced for D1's bind contract: null/undefined → null, primitives pass through, objects/arrays are JSON.stringify'd for you.

Limits & gotchas

  • Builder .where() supports equality + AND only. Anything more dynamic (IN, ranges, OR, joins) goes through flarelink.sql\`…\`.
  • Identifiers (table + column names) must match /^[A-Za-z_][A-Za-z0-9_]*$/ — anything else throws INVALID_IDENTIFIER before the request is sent.
  • Flarelink's auth tables share the same D1: user, account, verification, flarelink_config. Avoid those names for your own tables — you can read them like any other (flarelink.from('user')), but the dashboard locks writes to them.
  • All queries hit the single D1 bound to your auth Worker. Multi-D1 routing and browser-side queries with row-level security are deferred — see Architecture.
  • No batch([...]) API yet; use flarelink.sql\`…\` for multi-statement transactions. Errors are typed — see Error reference.

Need to create the tables you're querying? See Your schema & migrations.

Something unclear or missing? [email protected] llms-full.txt ↗