Show HN: Bun-sqlgen โ Type-safe raw SQL for Bun, no ORM
Introducing bun-sqlgen: Type-Safe Raw SQL for Bun
bun-sqlgen is a specialized type generator designed for Bun.sql queries. It allows developers to write raw SQL while maintaining strict type safety without the overhead of a full ORM.
The Core Philosophy: Why choose between the power of raw SQL and the safety of TypeScript?
bun-sqlgenbridges this gap by live-checking your queries against your actual database schema.
๐ Key Features & Benefits
Instead of relying on heavy ORMs or manually writing interfaces, bun-sqlgen automates the process.
- Zero-Effort Typing: Tag a query (e.g.,
sql.GetUser) and get fully-typed, null-safe results immediately. - No Generics: You don't have to pass complex generic types to your query functions.
- Real-World Validation: The codegen process validates queries against a live Postgres or SQLite instance.
- Fast Feedback Loop: It is optimized to run on every file save, ensuring that bad SQL or missing columns fail during the build phase rather than in production.
- Lightweight: No Docker containers are required for the validation process.
Database Compatibility
| Database | Supported | Requirement |
|---|---|---|
| PostgreSQL | โ | Real instance for validation |
| SQLite | โ | Real instance for validation |
๐ ๏ธ Workflow Architecture
The following diagram illustrates how bun-sqlgen transforms your SQL migrations into TypeScript definitions:
๐ Quick Start Guide
1. Installation
Add the package to your project using the Bun package manager:
bun add @ilbertt/bun-sqlgen
2. Setup Checklist
- Create a migrations folder (e.g.,
db/migrations/). - Define your schema in
.sqlfiles. - Wrap your Bun SQL client.
- Run the generator.
3. Implementation Example
Step A: Define your schema
In db/migrations/0001_init.sql:
CREATE TABLE users (
id bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
email text NOT NULL,
display_name text
);
Step B: Write your typed query
import { withTypes } from '@ilbertt/bun-sqlgen';
import { SQL } from 'bun';
// Wrap the standard Bun SQL client
const sql = withTypes(new SQL(Bun.sql));
export async function getUser(id: number) {
// Tag the query with .GetUser to trigger type generation
const [user] = await sql.GetUser`
SELECT id, email, display_name
FROM users
WHERE id = ${id}
`;
return user;
// Result is automatically typed as:
// { id: string; email: string; display_name: string | null }
}
Step C: Generate the types Run the following command in your terminal:
bun bun-sqlgen generate 'src/**/*.ts' --migrations db/migrations
This process creates a src/queries.gen.d.ts file. Note: This file should be committed to your version control.
๐ Technical Nuances
The mapping of database types to TypeScript can be represented as a function:
Because the tool checks the actual schema, if you attempt to access user.emial (a typo), tsc will throw a compile error. Similarly, because display_name is nullable in the database, TypeScript will flag user.display_name.length as a potential error unless you handle the null case.
๐ค Contributing & Project Info
- Language: 100% TypeScript.
- License: Unlicense.
- Documentation: Detailed guides on transactions, nullability overrides, and configuration are available in the main README.
- Guidelines: Please refer to
CONTRIBUTING.mdfor development setup and conventions.