Skip to content

Instantly share code, notes, and snippets.

@azpoint
Last active May 3, 2025 17:44
Show Gist options
  • Save azpoint/64ff3e92879dd41eb0964fd3d93c4a13 to your computer and use it in GitHub Desktop.
Save azpoint/64ff3e92879dd41eb0964fd3d93c4a13 to your computer and use it in GitHub Desktop.

🧠 Knex.js + PostgreSQL Table Options Cheat Sheet

🧾 Column Types (PostgreSQL Friendly)

Column Type Knex Method Notes
Primary ID table.increments('id') Auto-incremented integer (serial)
UUID table.uuid('id') You generate UUIDs manually or with gen_random_uuid()
String table.string('title', [length]) varchar, max 255 by default
Text table.text('content') Unlimited length
Integer table.integer('count') 4-byte signed integer
BigInt table.bigInteger('views') 8-byte integer
Float table.float('rating') Approx. number
Decimal table.decimal('price', 8, 2) Exact decimal – for currency
Boolean table.boolean('is_active') true / false
Date table.date('birth_date') Date only
Timestamp table.timestamp('created_at', { useTz: true }) With time zone
Timestamps table.timestamps(true, true) created_at, updated_at (default to now)
Enum table.enu('status', ['draft', 'published']) Postgres maps this to TEXT by default
JSON / JSONB table.json('data') / table.jsonb('data') For structured or searchable data

πŸ”— Relationships & Foreign Keys

Purpose Example
Foreign key table.integer('user_id').unsigned().references('id').inTable('users')
UUID foreign key table.uuid('user_id').references('id').inTable('users')
Cascade delete .onDelete('CASCADE')
Cascade update .onUpdate('CASCADE')

πŸ”’ Constraints & Indexes

Constraint Example
Required .notNullable()
Nullable .nullable()
Default value .defaultTo(true) or .defaultTo(knex.fn.now())
Unique .unique()
Primary key .primary()
Index .index()
Composite key .primary(['col1', 'col2'])

πŸ›  Table Options (Postgres-compatible)

Option Example
Drop column table.dropColumn('col')
Rename column table.renameColumn('old', 'new')
Add comment table.comment('Products table')
Set charset/collation Usually not needed in Postgres
Table-specific primary table.primary(['id', 'locale'])

βœ… Full Table Example – PostgreSQL Optimized

exports.up = function(knex) {
  return knex.schema.createTable('products', function(table) {
    table.increments('id').primary();                                // Auto ID
    table.string('name', 150).notNullable().unique();                // Required + unique name
    table.text('description');                                       // Optional
    table.decimal('price', 10, 2).notNullable();                     // Currency
    table.integer('stock').notNullable().defaultTo(0);              // Inventory count
    table.boolean('is_active').notNullable().defaultTo(true);        // Status
    table.enu('status', ['draft', 'published', 'archived'])          // Enum status
         .notNullable().defaultTo('draft');

    table.uuid('vendor_id')                                          // UUID foreign key
         .references('id').inTable('vendors')
         .onDelete('SET NULL')
         .onUpdate('CASCADE');

    table.jsonb('metadata');                                         // Searchable JSON
    table.timestamp('available_from', { useTz: true });              // Optional timestamp
    table.timestamps(true, true);                                    // created_at, updated_at

    table.index(['vendor_id']);                                      // Index for fast filtering
  });
};

exports.down = function(knex) {
  return knex.schema.dropTable('products');
};


---

# βœ… Migration Table Example – PostgreSQL Optimized

```js
// migrations/20250503121000_create_users_and_profiles.js

/**
 * This migration demonstrates common table options in Knex.
 */
export async function up(knex) {
  await knex.schema.createTable('users', (table) => {
    table.increments('id').primary(); // Auto-incrementing primary key
    table.string('username', 50).notNullable().unique(); // String with max length, required, unique
    table.string('email').notNullable().unique();        // Unique email
    table.string('password_hash').notNullable();         // Password hash
    table.boolean('is_active').defaultTo(true);          // Boolean flag with default
    table.timestamp('created_at').defaultTo(knex.fn.now()); // Timestamp with default
    table.timestamp('updated_at').defaultTo(knex.fn.now());
  });

  await knex.schema.createTable('profiles', (table) => {
    table.increments('id');
    table.integer('user_id').unsigned().references('id').inTable('users').onDelete('CASCADE');
    table.text('bio');                          // Text column
    table.string('avatar_url');                // Optional string
    table.date('birthdate');                   // Date type
    table.enu('gender', ['male', 'female', 'other']); // Enum
    table.jsonb('preferences');                // JSONB column (PostgreSQL only)
    table.timestamps(true, true);              // created_at and updated_at with defaults
  });
}

/**
 * Drops both tables if rolled back.
 */
export async function down(knex) {
  await knex.schema.dropTableIfExists('profiles');
  await knex.schema.dropTableIfExists('users');
}
// index.js
import express from 'express';
import db from './db.js';
const app = express();
const PORT = 3000;
app.use(express.json());
// πŸš€ Create a new user
app.post('/users', async (req, res) => {
try {
const [user] = await db('users')
.insert(req.body)
.returning('*');
res.status(201).json(user);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// πŸ“₯ Get all users
app.get('/users', async (req, res) => {
try {
const users = await db('users').select('*');
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// πŸ” Get a single user by ID
app.get('/users/:id', async (req, res) => {
try {
const user = await db('users').where({ id: req.params.id }).first();
if (user) res.json(user);
else res.status(404).json({ error: 'User not found' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// ✏️ Update a user
app.put('/users/:id', async (req, res) => {
try {
const [updatedUser] = await db('users')
.where({ id: req.params.id })
.update(req.body)
.returning('*');
if (updatedUser) res.json(updatedUser);
else res.status(404).json({ error: 'User not found' });
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// ❌ Delete a user
app.delete('/users/:id', async (req, res) => {
try {
const deleted = await db('users').where({ id: req.params.id }).del();
if (deleted) res.json({ message: 'User deleted' });
else res.status(404).json({ error: 'User not found' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Start server
app.listen(PORT, () => {
console.log(`πŸš€ Server running at http://localhost:${PORT}`);
});

πŸ“˜ Knex.js Cheat Sheet (with PostgreSQL)

Quick reference for using Knex.js with Node.js and PostgreSQL


βš™οΈ Project Setup

npm init -y
npm install knex pg
npx knex init

Example knexfile.js

module.exports = {
  development: {
    client: 'pg',
    connection: {
      host: '127.0.0.1',
      user: 'your_user',
      password: 'your_password',
      database: 'your_database'
    },
    migrations: {
      directory: './migrations'
    },
    seeds: {
      directory: './seeds'
    }
  }
};

βœ… Setup

// db.js
import knex from 'knex';
import config from './knexfile.js';

const db = knex(config.development);
export default db;

πŸ—οΈ Migrations

Create Migration File

npx knex migrate:make create_users_table
# Creates a new migration file with the name "create_users_table" to define changes to the database schema.

npx knex migrate:latest --knexfile db/knexfile.js
# Runs the latest migrations, applying any unapplied migrations to the database.

npx knex migrate:make migration_name --knexfile db/knexfile.js
# Creates a new migration file with the given "migration_name". This is the base file to define schema changes.

npx knex seed:make seed_name --knexfile db/knexfile.js
# Creates a new seed file with the name "seed_name" to populate the database with initial data.

npx knex seed:run --knexfile db/knexfile.js
# Executes all seed files, populating the database with data defined in the seed files.

npx knex migrate:up migration_name --knexfile db/knexfile.js
# Applies a specific migration by the name "migration_name". This is used when you want to manually run a migration.

npx knex migrate:down migration_name --knexfile db/knexfile.js
# Rolls back a specific migration by the name "migration_name". This is used to undo a previously applied migration.

npx knex migrate:rollback --all --knexfile db/knexfile.js
# Rolls back all migrations, undoing every migration that has been applied, essentially resetting the schema to its initial state.

### Migration Example
```js
exports.up = function(knex) {
  return knex.schema.createTable('users', function(table) {
    table.increments('id').primary();
    table.string('name');
    table.string('email').unique();
  });
};

exports.down = function(knex) {
  return knex.schema.dropTableIfExists('users');
};

Run Migrations

npx knex migrate:latest

Roll Back Migrations

npx knex migrate:rollback       # Roll back latest batch
npx knex migrate:rollback --all # Roll back all

🌱 Seeds

Create Seed File

npx knex seed:make seed_users

Seed File Example

exports.seed = async function(knex) {
  await knex('users').del();
  await knex('users').insert([
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ]);
};

Run Seeds

npx knex seed:run

πŸ” Query Builder Basics

Insert

await knex('users').insert({ name: 'Charlie', email: '[email protected]' });

Select

const users = await knex('users').select('*');

Where

const activeUsers = await knex('users').where('is_active', true);

Update

await knex('users').where({ id: 1 }).update({ name: 'Updated Name' });

Delete

await knex('users').where('id', 1).del();

πŸ”„ Transactions

await knex.transaction(async trx => {
  await trx('users').insert({ name: 'Alice' });
  await trx('accounts').insert({ user_id: 1, balance: 100 });
});

πŸ” SELECT

All rows

const users = await db('users').select('*');

Specific columns

const users = await db('users').select('id', 'name');

WHERE clause

const user = await db('users').where({ id: 1 }).first();

WHERE with operators

const activeUsers = await db('users')
  .where('is_active', true)
  .andWhere('created_at', '>', '2024-01-01');

WHERE IN

const users = await db('users').whereIn('id', [1, 2, 3]);

WHERE NULL

const users = await db('users').whereNull('deleted_at');

βž• INSERT

Single row

const [user] = await db('users')
  .insert({ name: 'Alice', email: '[email protected]' })
  .returning('*');

Multiple rows

const newUsers = await db('users')
  .insert([
    { name: 'Bob', email: '[email protected]' },
    { name: 'Carol', email: '[email protected]' }
  ])
  .returning('*');

✏️ UPDATE

const [updatedUser] = await db('users')
  .where({ id: 1 })
  .update({ name: 'Alice Updated' })
  .returning('*');

❌ DELETE

const deleted = await db('users')
  .where({ id: 1 })
  .del();

πŸ”’ COUNT

const [{ count }] = await db('users').count('id');

πŸ“Š AGGREGATE FUNCTIONS

const stats = await db('users')
  .select(db.raw('MIN(id), MAX(id), COUNT(*)'))
  .first();

πŸ“ LIMIT / OFFSET

const page = 2;
const limit = 10;
const users = await db('users')
  .limit(limit)
  .offset((page - 1) * limit);

πŸ“ ORDER BY

const users = await db('users').orderBy('created_at', 'desc');

🀝 JOIN

const posts = await db('posts')
  .join('users', 'posts.user_id', 'users.id')
  .select('posts.*', 'users.name');

πŸ§ͺ RAW SQL

const result = await db.raw('SELECT * FROM users WHERE email = ?', ['[email protected]']);

🧠 TRANSACTIONS

await db.transaction(async (trx) => {
  await trx('users').insert({ name: 'Temp', email: '[email protected]' });
  await trx('logs').insert({ action: 'user_created' });
});

πŸš€ RAW RETURNING

const [user] = await db('users')
  .insert({ name: 'Raw', email: '[email protected]' })
  .returning(['id', 'email']);

🧹 TRUNCATE

await db('users').truncate(); // Be careful: resets identity

πŸ’¬ Debugging

const users = await db('users')
  .where({ is_active: true })
  .debug(); // Logs generated SQL


πŸ“Œ Useful Commands

Task Command
Init knex config npx knex init
Make migration npx knex migrate:make migration_name
Run migrations npx knex migrate:latest
Roll back npx knex migrate:rollback
Create seed npx knex seed:make seed_name
Run seeds npx knex seed:run

πŸ“š Docs

Comments are disabled for this gist.