Loading ad...
NestJS Knex Example: Step-by-Step Guide to Building Scalable SQL Application

NestJS Knex Example: Step-by-Step Guide to Building Scalable SQL Application

Are you trying to use Knex.js with NestJS but feeling lost? You're not alone. While NestJS is packed with modern features, integrating it with SQL query builders like Knex requires a bit of setup. This beginner-friendly guide walks you through how to connect Knex with NestJS from scratch, covering configuration, migrations, query examples, real-world use cases and best practices. Whether you're using PostgreSQL, MySQL or SQLite, this comprehensive tutorial will help you build powerful and scalable SQL-based applications using Knex and NestJS.

Dev Orbit

Dev Orbit

August 2, 2025

Introduction to SQL with NestJS

In a backend ecosystem dominated by ORMs like TypeORM and Sequelize, it's easy to overlook the power of raw SQL and lightweight query builders. NestJS—a framework known for its structured architecture—works well with both.

But sometimes, developers want more control, faster performance and less abstraction. That’s where Knex.js comes in. Unlike heavy ORMs, Knex gives you the freedom to write raw, optimized SQL while still offering helpful utilities like migrations and query builders.


What is Knex.js?

Knex.js is a SQL query builder for Node.js that supports several relational databases like:

  • PostgreSQL

  • MySQL / MariaDB

  • SQLite3

  • MSSQL

It provides a clean, chainable syntax for writing SQL queries in JavaScript. While it’s not an ORM, Knex allows you to manage migrations, transactions and connections—making it ideal for projects that need SQL control without ORM overhead.


Benefits of Using Knex with NestJS

Here’s why developers often pair Knex with NestJS instead of an ORM:

Advantage

Explanation

Lightweight

No heavy abstractions or complex models

Full SQL Control

Easily write raw queries when needed

Better Performance

No hidden joins or auto-loading issues

Database Flexibility

Easily switch between databases

Scalable Architecture

Ideal for microservices and data-centric apps


Setting Up a New NestJS Project

To get started, create a new NestJS project:

npm i -g @nestjs/cli
nest new nest-knex-app
cd nest-knex-app

Choose any package manager (npm/yarn) and clear out any boilerplate modules if necessary.


Installing Knex and Required Dependencies

Let’s install Knex and a SQL driver. For this example, we'll use PostgreSQL:

npm install knex pg

If you're using another DB:

  • MySQL: npm install mysql2

  • SQLite: npm install sqlite3

To enable migrations and CLI support, you can also install Knex globally:

npm install -g knex

Configuring Knex in a NestJS App

Create a knexfile.js in your project root:

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

Add this to your package.json scripts:

"scripts": {
  "migrate": "knex migrate:latest --knexfile knexfile.js",
  "rollback": "knex migrate:rollback --knexfile knexfile.js"
}

Creating and Running Migrations

Create a migration to define your database schema:

knex migrate:make create_users_table --knexfile knexfile.js

CopyEdit

knex migrate:make create_users_table --knexfile knexfile.js

Edit the file in migrations/:

exports.up = function(knex) {
  return knex.schema.createTable('users', (table) => {
    table.increments('id');
    table.string('email').notNullable().unique();
    table.string('name');
    table.timestamps(true, true);
  });
};

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

Run the migration:

npm run migrate

Building a KnexService in NestJS

Create a new service that wraps Knex:

nest g service knex

In knex.service.ts:

import { Injectable, OnModuleInit } from '@nestjs/common';
import knex from 'knex';
import * as config from '../../knexfile';

@Injectable()
export class KnexService implements OnModuleInit {
  private db;

  onModuleInit() {
    this.db = knex(config.development);
  }

  get connection() {
    return this.db;
  }
}

Now you can inject KnexService into any module and use .connection to access the Knex instance.


Writing Basic SQL Queries Using Knex

Here’s how to use Knex in a controller or service:

const users = await this.knexService.connection('users')
  .select('*')
  .where({ email: '[email protected]' });

await this.knexService.connection('users').insert({
  email: '[email protected]',
  name: 'New User'
});

You can chain queries for sorting, filtering and pagination.


Knex with DTOs and Validation in NestJS

Use DTOs for type safety and validation:

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsOptional()
  @IsString()
  name?: string;
}

Combine DTOs with your controller logic for cleaner and safer inputs.


Knex Query Examples by Use Case

Now let’s explore practical, real-world examples using Knex with NestJS:

1. Pagination

const users = await this.knexService.connection('users')
  .select('*')
  .limit(10)
  .offset(20); // For page 3 (assuming 10 per page)

2. Search and Filtering

const results = await this.knexService.connection('users')
  .where('name', 'ilike', `%john%`)
  .andWhere('email', 'like', '%@gmail.com');

3. Joins

const posts = await this.knexService.connection('posts')
  .join('users', 'users.id', 'posts.user_id')
  .select('posts.*', 'users.name as authorName');

4. Transactions

await this.knexService.connection.transaction(async trx => {
  await trx('users').insert({ email: '[email protected]' });
  await trx('logs').insert({ action: 'User created' });
});

These examples show how Knex handles complex SQL tasks with clean, readable syntax.


Error Handling with Knex in NestJS

SQL can fail for various reasons—bad data, missing tables or constraint violations. NestJS makes it easy to manage these errors centrally.

Basic Try-Catch

try {
  await this.knexService.connection('users').insert({ email: '[email protected]' });
} catch (error) {
  throw new InternalServerErrorException(error.message);
}

Global Exception Filters

For consistent error handling, use NestJS filters:

@Catch(QueryFailedError)
export class DatabaseExceptionFilter implements ExceptionFilter {
  catch(exception: QueryFailedError, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    response.status(500).json({ message: exception.message });
  }
}

Testing Knex Queries in NestJS

To write tests, isolate logic in services and mock the Knex connection.

Mock KnexService

const mockKnexService = {
  connection: jest.fn().mockReturnValue({
    select: jest.fn().mockReturnValue([{ id: 1, email: '[email protected]' }]),
  }),
};

Unit Test Example

it('should fetch users', async () => {
  const users = await service.getUsers();
  expect(users).toHaveLength(1);
});

Make sure you use test databases or mocking for safe and repeatable tests.


Switching Between Development and Production Databases

Use environment variables to control which Knex config gets loaded:

const config = require('./knexfile')[process.env.NODE_ENV || 'development'];

Maintain separate .env files for:

  • Development

  • Testing

  • Production

This ensures proper isolation of data environments and reduces risk of destructive migrations.


Real-World Use Cases of Knex with NestJS

Here’s where this combo shines:

Use Case

Why Knex Works Well

SaaS platforms

Precise query control, better indexing

Admin dashboards

Advanced filtering and joining

Reporting engines

Optimized raw SQL queries

Microservices

Lean, fast SQL operations without ORM bloat

Knex is especially useful when performance and transparency are top priorities.


Common Pitfalls and Troubleshooting Tips

⚠️ Common Mistakes:

  • Forgetting to run migrations.

  • Misconfigured database credentials.

  • Query returning undefined due to missing await.

✅ Tips:

  • Always wrap DB calls in try/catch.

  • Log Knex queries during development using .debug().

  • Use tools like PostgreSQL EXPLAIN to analyze slow queries.


FAQs About NestJS Knex Example

1. Is Knex.js an ORM?

No. Knex is a query builder—it helps write SQL with JS syntax but doesn’t manage models or relationships like an ORM.

2. Can I use Knex with TypeScript?

Absolutely. Knex has full TypeScript support and you can define your own types or interfaces for result sets.

3. Can I use raw SQL in Knex?

Yes, Knex supports raw queries:

await knex.raw('SELECT * FROM users WHERE id = ?', [1]);

4. Is Knex faster than TypeORM?

In many cases, yes. Knex is lightweight and doesn’t carry the overhead of models, decorators or auto-relations.

5. Can I switch to another database easily?

Yes, Knex supports multiple SQL dialects. You just need to change the client and connection config.

6. Should I use Knex for all NestJS projects?

Not necessarily. Use it when you need SQL-level control or want to avoid ORM abstraction for performance or complexity reasons.


Conclusion: Building Powerful SQL Apps with NestJS + Knex

If you're aiming to build structured, scalable SQL applications with complete control, the combination of NestJS + Knex is a game changer.

NestJS provides a clean, modular architecture ideal for enterprise applications, while Knex gives you the flexibility to write efficient, optimized SQL queries without the heaviness of an ORM.

Whether you're building a microservice, dashboard, reporting tool or a production-grade SaaS product—this stack enables rapid development, strict typing and full performance visibility.

Start small, follow the best practices and you’ll unlock the full potential of relational databases in a modern Node.js application.

Loading ad...
Dev Orbit

Written by Dev Orbit

Follow me for more stories like this

Enjoyed this article?

Subscribe to our newsletter and never miss out on new articles and updates.

More from Dev Orbit

Raed Abedalaziz Ramadan: Steering Saudi Investment Toward the Future with AI and Digital Currencies

Raed Abedalaziz Ramadan: Steering Saudi Investment Toward the Future with AI and Digital Currencies

In an era marked by rapid technological advancements, the intersection of artificial intelligence and digital currencies is reshaping global investment landscapes. Industry leaders like Raed Abedalaziz Ramadan are pioneering efforts to integrate these innovations within Saudi Arabia’s economic framework. This article delves into how AI and digital currencies are being leveraged to position Saudi investments for future success, providing insights, strategies and practical implications for stakeholders.

9 Real-World Python Fixes That Instantly Made My Scripts Production-Ready

9 Real-World Python Fixes That Instantly Made My Scripts Production-Ready

In this article, we explore essential Python fixes and improvements that enhance script stability and performance, making them fit for production use. Learn how these practical insights can help streamline your workflows and deliver reliable applications.

Temperature, Top-P, Top-K — Explained One More Time

Temperature, Top-P, Top-K — Explained One More Time

This comprehensive guide delves into the intricacies of temperature, top-p, and top-k parameters in AI language models. Whether you're a developer or researcher, you'll learn how to leverage these settings to improve your model's performance and get the most out of AI-generated content.

10 JavaScript Quirks That Look Wrong (But Are Actually Right)

10 JavaScript Quirks That Look Wrong (But Are Actually Right)

This article dives deep into ten surprising quirks of JavaScript that might confuse developers, especially those new to the language. From unexpected behavior with type coercion to peculiarities in operator precedence, we will clarify each aspect with real-world examples and practical implications. By understanding these quirks, developers can write cleaner and more efficient code, avoiding common pitfalls along the way.

Mastering Git Hooks for Automated Code Quality Checks and CI/CD Efficiency

Mastering Git Hooks for Automated Code Quality Checks and CI/CD Efficiency

Automate code quality and streamline your CI/CD pipelines with Git hooks. This step-by-step tutorial shows full-stack developers, DevOps engineers, and team leads how to implement automated checks at the source — before bad code ever hits your repositories.

Mistral AI Enhances Le Chat with Voice Recognition and Powerful Deep Research Capabilities

Mistral AI Enhances Le Chat with Voice Recognition and Powerful Deep Research Capabilities

In an era where communication and information retrieval are pivotal to our digital interactions, Mistral AI has raised the bar with its latest upgrades to Le Chat. By integrating sophisticated voice recognition and advanced deep research capabilities, users will experience unparalleled ease of use, as well as the ability to access in-depth information effortlessly. This article delves into how these innovations can transform user experiences and the broader implications for developers and AI engineers.

Have a story to tell?

Join our community of writers and share your insights with the world.

Start Writing
Loading ad...