effql is a sqlc-style TypeScript code generator for effect / @effect/sql.
It keeps a SQL-first workflow, uses Postgres introspection to infer types, and emits Effect-native code built around Schema and SqlSchema.*.
@effql/cli— CLI package providing theeffqlcommand@effql/core— config loading, SQL parsing, Postgres analysis, and code generation
npm install -D @effql/cli @effql/corepnpm add -D @effql/cli @effql/coreBootstrap a project:
npx @effql/cli init
npx @effql/cli init --config ./effql.config.tsThis creates:
effql.config.tssql/queries.sqlpackage.jsonif one does not already exist
Installed locally:
npx effql init
npx effql generate
npx effql generate --config ./effql.config.tsOne-off without installing:
npx @effql/cli generate
npx @effql/cli generate --config ./effql.config.tsAlso works with pnpm:
pnpm dlx @effql/cli generateYes — npx works because @effql/cli publishes the effql bin.
Try the example in two commands:
vp run -r build
vp run @effql/example-basic#generateThen start the example API:
vp run @effql/example-basic#startOr run the full smoke test used by CI:
pnpm run example:smokeeffql uses code-based config:
import { defineConfig } from "@effql/core";
export default defineConfig({
dialect: "postgres",
db: {
url: process.env.DATABASE_URL!,
},
queries: ["./sql/**/*.sql"],
outDir: "./generated",
});Supported config filenames:
effql.config.tseffql.config.mtseffql.config.jseffql.config.mjseffql.config.ctseffql.config.cjs
-- name: CreateUser :one
INSERT INTO users (id, email, created_at)
VALUES (@id::uuid, @email::text, now())
RETURNING id, email, created_at;
-- name: GetUser :one
SELECT id, email, created_at
FROM users
WHERE id = @id::uuid;Starter sql/queries.sql contains a simple Healthcheck query you can edit right away.
Generated modules export:
*ParamsSchema*ResultSchema*Params/*Resulttype aliases- raw
*Sqlstrings - executable
SqlSchema.*wrappers
export const CreateUserResultSchema = Schema.Struct({
id: Schema.UUID,
email: Schema.String,
created_at: Schema.DateFromSelf,
});
export const createUser = SqlSchema.single({
Request: CreateUserParamsSchema,
Result: CreateUserResultSchema,
execute: (request) =>
Effect.flatMap(SqlClient.SqlClient, (sql) =>
sql.unsafe(createUserSql, [request.id, request.email]),
),
});See examples/basic for the easiest end-to-end demo:
compose.yamlstarts Postgres on127.0.0.1:54329schema.sqlcreates and seedsuserssql/queries.sqldefines CRUD queriesgenerated/index.tsis committed generated outputsrc/httpApi.tsandsrc/server.tsshow runtime usage
This is an early Postgres-only MVP.
What works today:
- TS / JS config via
defineConfig() - query annotations:
:one,:maybeOne,:many,:exec - named params via
@param - Postgres-backed type inference
- generated
Schemaexports andSqlSchema.single/findOne/findAll/voidwrappers - self-contained CRUD example with Docker Compose and an Effect HTTP API
Current MVP limitations:
- Postgres only
- generation requires a live database connection
- named params currently work best with explicit casts, for example
@id::uuid - nullability inference is intentionally conservative
- output is currently a single generated module per target
- API / config shape may still evolve before a stable release
A GitHub Actions release workflow publishes the npm packages when a GitHub release is marked as published.
Before using it:
- add an
NPM_TOKENrepository secret if you keep token-based publishing - make sure you own/publish to both
@effql/cliand@effql/coreon npm - create releases with tags that match the package versions, for example
v0.1.1
The release workflow:
- installs dependencies
- verifies the release tag matches
packages/cliandpackages/coreversions - builds, lints, formats, tests, and runs the example smoke test
- publishes
@effql/core - publishes
@effql/cli
vp install
vp lint
vp fmt
vp test
vp run -r build
pnpm run example:smoke