D1 aligns run result types with its runtime
Updated Workers declarations expose the rows D1 already returns from run(). The correction makes a runtime compatibility decision visible to TypeScript callers.
D1's run() method returns query rows, but its TypeScript declaration had continued describing a response without them. Cloudflare's July 26 update corrects that mismatch in @cloudflare/workers-types version 4.20240725.0. A caller can now describe the row type and consume the result without treating real runtime behavior as an exception to the declared interface.
The release note identifies the old return type as D1Response and the corrected type as D1Result. The distinction concerns query results as well as metadata. This is a declaration correction, so it should not be read as an announcement that the service only started returning rows today.
I like SQLite's direct relationship between a query and its result. A hosted wrapper has to preserve that clarity across another language interface. When the wrapper returns data that its declarations omit, application authors are left deciding whether the runtime or the compiler is the better description of the API.
The earlier compatibility decision matters
The background is recorded in D1's February 16 change. Cloudflare restored D1Result rows to run() after briefly changing its runtime response earlier that month. It said a future move to the originally intended metadata-oriented result would be gated behind a compatibility date.
July's correction brings the declarations into agreement with that restored behavior. Runtime compatibility and static declarations are separate deliverables, and both need to describe the same contract for TypeScript callers. Keeping the response stable protects deployed code. Updating the declarations protects the source code that developers compile against it.
An outdated return type creates pressure to work around the compiler. A programmer can see rows in a response while the type system provides no supported way to access them. An assertion can suppress that disagreement locally, but it does not tell the next reader whether the program relies on an accidental response or an officially supported field.
The release note removes that ambiguity for this version. run() returns a result with rows. The declaration now provides the corresponding generic result shape. Applications can express that dependency directly and let ordinary property checking work over the declared response.
The declaration includes the row type
The published declaration file gives run() a generic type parameter, with Record<string, unknown> as the default. Its return value is a promise of D1Result<T>. The same file gives all() the corresponding generic result form.
This allows an application to name the properties it expects from the SQL projection. The following example uses a query with a known alias so the relationship between SQL and the row interface is visible. It illustrates the declarations in the released package.
type AnswerRow = { answer: number };
async function readAnswer(db: D1Database) {
const result = await db
.prepare("SELECT 42 AS answer")
.run<AnswerRow>();
return result.results[0]?.answer;
}
The type parameter describes the expected row. It does not parse the SQL expression or prove that a modified query still returns an answer number. Changing the projection requires keeping the declared row interface consistent. That remaining responsibility is different from a declaration that prevents access to rows the API deliberately supplies.
The optional access in the example also makes the possibility of a missing array element explicit in the consuming expression. It shows result consumption without asserting that every possible statement returns a first row. The query shown is deliberately small enough that its selected value is evident from the SQL itself.
Method names cannot replace response contracts
The name run() can suggest that a caller only cares about completing execution. D1's history shows why an intuition about the name is insufficient. Cloudflare intended a narrower response, but deployed applications depended on rows, and the runtime reverted to providing them. The current declaration needs to describe that chosen behavior.
This also explains why the change should not be summarized as an instruction to replace every run() call with all(). Both methods have declared result rows in the published file. An application may choose a method for clarity, but the maintenance change repairs the type of an existing method rather than requiring a source migration to a different one.
I consider accurate declarations part of the API's operational reliability. Type checking happens before a Worker handles a request, so a mismatch can make a valid runtime dependency look unsupported during development. Correcting it reduces the need for local assertions whose purpose disappears once the declaration catches up.
The concrete adoption step is selecting a Workers types package that includes the correction. The dated package named in the release supplies a fixed reference for the signature, which is more precise than relying on whichever declarations an editor happens to load. With that version, the source-level contract and D1's restored runtime response agree that run() can return query rows alongside execution information.
The declaration defines D1Result<T> as an intersection with D1Response, adding a results array of T. Metadata remains available through the response portion. That structure explains why correcting the type adds row access without discarding the execution information callers already use.