Skip to content

Getting Started ​

Install ​

bash
npm install nestjs-duckdb

Quick start ​

Register the module in your app:

ts
import { Module } from '@nestjs/common';
import { DuckDbModule } from 'nestjs-duckdb';

@Module({
  imports: [
    DuckDbModule.forRoot({
      database: ':memory:', // or a path like './my.db'
    }),
  ],
})
export class AppModule {}

Then inject DuckDbService anywhere:

ts
import { Injectable } from '@nestjs/common';
import { DuckDbService } from 'nestjs-duckdb';

@Injectable()
export class AnalyticsService {
  constructor(private readonly duckDb: DuckDbService) {}

  async getTopUsers() {
    return this.duckDb.query('SELECT * FROM users ORDER BY score DESC LIMIT 10');
  }
}

Parameterized queries ​

Always use ? placeholders for any value that comes from user input, request params, or anywhere outside your own code. query() and run() pass extra arguments straight through to the DuckDB driver as bound parameters:

ts
// Safe - the id is bound as a parameter, not concatenated into the SQL string
await this.duckDb.query('SELECT * FROM users WHERE id = ?', userId);

await this.duckDb.run(
  'INSERT INTO people (id, name) VALUES (?, ?)',
  id,
  name,
);

Never build SQL with string interpolation or concatenation using untrusted input:

ts
// Unsafe - vulnerable to SQL injection
await this.duckDb.query(`SELECT * FROM users WHERE id = ${userId}`);

DuckDbService executes whatever SQL string it's given - it has no way to tell a trusted static query apart from one built from user input, so this protection has to come from how you call query()/run() in your own code.

Next steps ​

Typed DuckDB configuration ​

The config option is fully typed against real DuckDB settings, so you get autocomplete and type-checking instead of a loose string map:

ts
DuckDbModule.forRoot({
  database: './my.db',
  config: {
    access_mode: 'read_write', // 'automatic' | 'read_only' | 'read_write'
    threads: 4,
    max_memory: '2GB',
    temp_directory: '/tmp/duckdb',
  },
});

Any DuckDB setting not explicitly typed still works via the index signature, e.g. config: { some_new_setting: 'value' }.

Released under the MIT License.