Skip to content
Back to skills

Knex

ASecurity

Knex.js is a SQL query builder for Node.js with a chainable API, schema migrations, seeds and transactions for PostgreSQL, MySQL, MariaDB, SQLite and MSSQL. Use when writing queries without a full ORM, setting up knexfile.js and migrations, running knex migrate:latest, building joins, subqueries and transactions, or typing results with TypeScript.

  • 142 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 29, 2026
databasestypescriptgobashsqlnodegitapidatabase

Works with

  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill knex --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Knex?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Knex
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-knex/badge)](https://www.skillsdirectory.com/skills/terminalskills-knex)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: knex
description: >-
  Knex.js is a SQL query builder for Node.js with a chainable API, schema migrations, seeds and transactions for PostgreSQL, MySQL, MariaDB, SQLite and MSSQL. Use when writing queries without a full ORM, setting up knexfile.js and migrations, running knex migrate:latest, building joins, subqueries and transactions, or typing results with TypeScript.
license: Apache-2.0
compatibility: "Node.js 16+, knex 3.x plus one database driver (pg, mysql2, better-sqlite3, sqlite3, tedious)"
metadata:
  author: terminal-skills
  version: 1.1.0
  category: development
  repository: https://github.com/knex/knex
  tags:
    - query-builder
    - sql
    - database
    - migrations
    - node
---

# Knex.js — SQL Query Builder for Node.js

## Overview

Knex ([knexjs.org](https://knexjs.org), `knex/knex`) builds parameterized SQL through a chainable API and ships a migration and seed CLI. It is the layer under Objection.js and Bookshelf. Checked against knex 3.3.0 (26 June 2026; 3.0 dropped Node < 16, 3.2 added migration lifecycle hooks, 3.3 added MariaDB driver support). Queries below were run against SQLite with the same builder calls.

## Instructions

### Install and connect

```bash
npm install knex pg            # PostgreSQL; other drivers: mysql2, better-sqlite3, sqlite3, tedious (MSSQL)
npx knex init -x ts            # creates knexfile.ts (use `npx knex init` for knexfile.js)
```

```typescript
import knex from "knex";

export const db = knex({
  client: "pg",
  connection: process.env.DATABASE_URL,
  pool: { min: 2, max: 20 },
});
```

Use `client: "better-sqlite3"` with `useNullAsDefault: true` for SQLite. Call `await db.destroy()` when a script finishes, or the process hangs on the open pool.

### Queries

```typescript
interface User { id: number; name: string; email: string; role: string }

const posts = await db("posts")
  .join("users", "posts.author_id", "users.id")
  .select("posts.*", "users.name as author_name")
  .where("posts.published", true)
  .orderBy("posts.created_at", "desc")
  .limit(10).offset(20);

const [user] = await db<User>("users")
  .insert({ name: "Alice Morgan", email: "alice.morgan@northwind.io" })
  .returning("*");                              // PostgreSQL, SQLite 3.35+, MSSQL; not MySQL

await db("users").where({ id: user.id }).update({ name: "Alice M." });
await db("users").where({ id: user.id }).del();

const recent = await db("users")
  .whereIn("id", db("posts").select("author_id").where("created_at", ">", thirtyDaysAgo));

const monthly = await db("orders")
  .select(db.raw("DATE_TRUNC('month', created_at) as month"))   // PostgreSQL function
  .sum("amount as total").count("* as orders")
  .groupByRaw("DATE_TRUNC('month', created_at)")
  .orderBy("month", "desc");
```

`db<User>("users")` types the result rows. On PostgreSQL `count` and `sum` come back as strings (bigint/numeric); cast in the query or in code. `db.raw(sql, [values])` returns the driver's native result (for `pg`, read `result.rows`). Inspect SQL with `.toQuery()` or `.toSQL()`.

### Transactions

```typescript
await db.transaction(async (trx) => {
  const [order] = await trx("orders").insert({ user_id: 1, total: 99.99 }).returning("*");
  await trx("order_items").insert(items.map((i) => ({ ...i, order_id: order.id })));
  await trx("users").where({ id: 1 }).decrement("balance", 99.99);
});   // commits when the callback resolves, rolls back when it throws
```

Every statement inside must use `trx`, not `db`, or it runs outside the transaction.

### Migrations and seeds

```bash
npx knex migrate:make create_users_table -x ts   # timestamped file in ./migrations
npx knex migrate:latest                          # run all pending
npx knex migrate:status                          # list applied / pending
npx knex migrate:rollback                        # undo the last batch
npx knex seed:make seed_users && npx knex seed:run
npx knex migrate:latest --env production         # pick a knexfile environment
```

```typescript
// migrations/20261002120000_create_users_table.ts
import type { Knex } from "knex";

export async function up(knex: Knex): Promise<void> {
  await knex.schema.createTable("users", (t) => {
    t.increments("id");
    t.string("name", 100).notNullable();
    t.string("email").notNullable().unique();
    t.enu("role", ["user", "admin"]).defaultTo("user");
    t.timestamps(true, true);                    // created_at / updated_at defaulting to now
  });
  await knex.schema.createTable("posts", (t) => {
    t.increments("id");
    t.string("title").notNullable();
    t.boolean("published").defaultTo(false);
    t.integer("author_id").unsigned().references("id").inTable("users").onDelete("CASCADE");
    t.index(["author_id", "published"]);
  });
}

export async function down(knex: Knex): Promise<void> {
  await knex.schema.dropTable("posts");
  await knex.schema.dropTable("users");
}
```

TypeScript migrations need a loader the CLI can find: install `tsx` and run `NODE_OPTIONS="--import tsx" npx knex migrate:latest` (ts-node also works), and set `migrations: { extension: "ts" }` in the knexfile. Confirmed with tsx on Node 24.

## Examples

### Example 1: "Add a users table and apply it"

```bash
npm install knex pg
npx knex init -x ts
npx knex migrate:make create_users_table -x ts
# paste the up/down functions above, then
NODE_OPTIONS="--import tsx" npx knex migrate:latest
```

Output: `Batch 1 run: 1 migrations`. `migrate:status` then lists `20261002120000_create_users_table.ts` as completed.

### Example 2: "Move money between two accounts atomically"

```typescript
await db.transaction(async (trx) => {
  const { balance } = await trx("accounts").where({ id: 7 }).forUpdate().first();
  if (balance < 250) throw new Error("insufficient funds");   // triggers rollback
  await trx("accounts").where({ id: 7 }).decrement("balance", 250);
  await trx("accounts").where({ id: 12 }).increment("balance", 250);
});
```

Either both updates persist or neither does. `forUpdate()` locks the row on PostgreSQL and MySQL.

## Guidelines

- Pass user input as bindings (`where({ email })`, `raw("... ?", [value])`), never by string concatenation. Identifiers in `raw` need `??`.
- Change schema only through migrations; never edit a migration that has already run in shared environments, add a new one.
- Keep one `knex` instance per process; a new pool per request exhausts connections.
- Match `pool.max` to the database's connection limit divided by app instances.
- Knex does not map rows to classes or manage relations; use Objection.js or an ORM if you need that.
- MySQL has no `returning`; read `insertId` from the result instead.

Files in this skill

  • SKILL.md4.6 KB
  • _scores.json1.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.