Skip to content

Use sqlc-gen-typescript-native for TypeScript support - #4611

Closed
touzoku wants to merge 2 commits into
sqlc-dev:mainfrom
bonakodo:migrate-to-typescript-native-wasm
Closed

Use sqlc-gen-typescript-native for TypeScript support#4611
touzoku wants to merge 2 commits into
sqlc-dev:mainfrom
bonakodo:migrate-to-typescript-native-wasm

Conversation

@touzoku

@touzoku touzoku commented Sep 8, 2026

Copy link
Copy Markdown

This switches the TypeScript links in the README and language support table to sqlc-gen-typescript-native, marks SQLite support as Beta, and re-enables TypeScript CI. The job pins v0.4.0 by commit and tests it with the sqlc built from this checkout.

The current plugin builds TypeScript syntax trees and prints them through the TypeScript compiler inside Javy. The replacement implements generation directly in WebAssembly text. It uses the same sqlc plugin protocol, without an embedded JavaScript runtime or TypeScript compiler. This PR changes the plugin integration and docs; it requires no changes to sqlc's compiler or plugin API. See the existing build and new implementation.

The published WASM file drops from 72,685,305 bytes to 86,712 bytes: 99.88% smaller. These are the files from sqlc-gen-typescript v0.1.3 and sqlc-gen-typescript-native v0.4.0, verified against their published SHA-256 checksums.

I measured complete sqlc generate runs for both releases using the same PostgreSQL fixtures. The releases were measured in separate runs:

PostgreSQL fixture Cache v0.1.3 Native v0.4.0
1 table, 8 queries Cold 921.9 ms 128.8 ms
1 table, 8 queries Warm 485.9 ms 37.6 ms
100 tables, 800 queries Cold 8,562.7 ms 350.6 ms
100 tables, 800 queries Warm 8,298.7 ms 269.4 ms

These are medians on an Apple M1 Max running macOS 26.6.2, using sqlc commit 23e357a414310aa8846e64624da8b8a626b3a610, built with Go 1.26.5. Both plugins received the same schemas, queries, and runtime: node / driver: pg options. Cold results use three runs with fresh SQLCCACHE directories; warm results use seven runs after one untimed warmup. Downloads sit outside the timer; SQL analysis, plugin loading, generation, and file writes sit inside it. Every run must emit all expected query functions with the same output as that plugin's other runs. These numbers measure generation, not database query speed.

The feature gains also matter:

  • Deno SQLite and exact integers. It adds @bonakodo/sqlite support and an opt-in native mode for both SQLite drivers, with bigint integers, boolean/date conversions, and synchronous calls that work inside transaction callbacks. Upstream main already has better-sqlite3; the new Deno driver and native value handling extend that support.
  • More query commands. It handles :execrows and :execresult, and adds :execlastid for better-sqlite3. The existing plugin's dispatch handles only :one, :many, :exec, and :execlastid; its SQLite driver rejects the last one. See dispatch and SQLite output.
  • Shared types and custom conversions. It emits table models, enum values and types, and typed JSON. Column, database-type, and query overrides can supply application types and codecs. Conversion failures include field and query context.
  • Optional API controls. Connection-bound query factories, types-only output, nullable-argument options, and control over exported SQL constants let applications choose the API they need. PostgreSQL pg/postgres.js and MySQL mysql2 remain supported. The plugin README documents the options and driver behavior.

Generated TypeScript size depends on the workload. Native v0.4.0 shares query types, encoders, decoders, and field metadata across SQL files. It splits runtime helpers into a common file and one file per engine, and emits only the helpers the queries use. Running the same PostgreSQL fixtures gives:

Plugin 1 table, 8 queries 100 tables, 800 queries
sqlc-gen-typescript v0.1.3 7,620 bytes 762,000 bytes
Native v0.4.0 14,193 bytes 634,032 bytes

The small fixture remains larger than the old plugin; the large fixture is now 16.8% smaller. These totals include all generated files before bundling.

Migration starts with changing the WASM URL and checksum, keeping the shared runtime, driver, and mysql2 options, then regenerating and type-checking the application. Output is not byte-compatible: it adds files and corrects some field types and names. The module also uses fixed 64 MiB memory, with 16 MiB limits on the request and combined generated file contents, and a 1,024-file limit. The migration notes cover these differences and the other capacity limits.

Local validation passed: the sqlc build, the pinned plugin's full integration task, generated TypeScript and Deno checks, the 100-table/800-query/202-override test, 42 Deno runtime tests, 11 Node tests, 11 Bun tests, the example's sqlc diff, and actionlint. SQLite tests execute real queries; server-driver adapter tests use test doubles. Live PostgreSQL/MySQL tests remain unverified. The TypeScript CI job passed on the updated PR commit.

Point the language links to the native plugin and mark SQLite support as
beta. Remove the old plugin name from historical changelog entries while
keeping their original meaning.

Enable TypeScript CI against v0.3.0, pinned by commit. Build sqlc from the
current checkout and run the plugin's generation, type and runtime tests,
then check the generated Deno SQLite example with sqlc diff.
@touzoku

touzoku commented Sep 9, 2026

Copy link
Copy Markdown
Author

@yshrsmz @kyleconroy @shinshin86 @woowenjun99 tagging for visibility

@kyleconroy kyleconroy closed this Sep 9, 2026
@kyleconroy

Copy link
Copy Markdown
Collaborator

I'm happy to add sqlc-gen-typescript-native to the community plugins section, but I'm not going to be replacing the existing TypeScript support.

@touzoku

touzoku commented Sep 9, 2026

Copy link
Copy Markdown
Author

@kyleconroy The plugin hasn’t seen any updates in two years, and its current functionality is significantly more limited than what I’ve implemented here. In practice, the existing TypeScript support is very minimal, which is exactly why I opened this PR.

I’d suggest reconsidering this. I don’t mind if this work eventually gets moved or merged upstream into the plugin, but at the moment it doesn’t appear that anyone is actively working on TypeScript codegen there.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants