Get from zero to a working query with one table, one insert, and one typed select.
This tutorial uses better-sqlite3 because it is the shortest local setup path. The same Engine and builder APIs work with the MySQL, PostgreSQL, and PGlite connection packages.
- Node.js 22 or newer
yarnbetter-sqlite3@stackpress/inquire@stackpress/inquire-sqlite3
yarn add @stackpress/inquire @stackpress/inquire-sqlite3 better-sqlite3import sqlite from 'better-sqlite3';
import connect from '@stackpress/inquire-sqlite3';
const resource = sqlite(':memory:');
const engine = connect(resource);connect() wraps the native driver and gives you an Engine that speaks the right SQL dialect.
await engine.create('users')
.addField('id', { type: 'integer', autoIncrement: true })
.addField('email', { type: 'string', length: 255, nullable: false })
.addField('name', { type: 'string', length: 255, nullable: false })
.addField('active', { type: 'boolean', default: true })
.addPrimaryKey('id')
.addUniqueKey('users_email_unique', 'email');create() returns an awaitable builder. When you await it, Inquire generates SQL for the current dialect and runs it in a transaction.
await engine.insert('users').values([
{ email: 'ada@example.com', name: 'Ada', active: true },
{ email: 'grace@example.com', name: 'Grace', active: false }
]);insert() also returns an awaitable builder. Use .values() with one object or an array of objects.
type UserRow = {
id: number;
email: string;
name: string;
active: number;
};
const users = await engine.select<UserRow>([
'id',
'email',
'name',
'active'
])
.from('users')
.where('active = ?', [1])
.order('name');
console.log(users);With SQLite, booleans are stored as integers. Other dialects may format the same value differently, but the builder API stays the same.
You should get one row back for Ada.
If that works, you have the main flow:
- schema creation with
create() - writes with
insert() - typed reads with
select<T>()
- The connection package chose the dialect for you.
- The
Enginecreated builders for schema and query operations. - Each builder stayed plain and explicit. You defined table names, columns, and filters yourself.
- No model layer was created. Inquire helps you build SQL. It does not act like an ORM.
- Read Mental model to understand the moving parts.
- Read Schema changes to update existing tables.
- Read Raw SQL and transactions when you need custom SQL.
- Use the API reference for exact method details.