eloquent-filter, redesigned for NestJS

Stop writing if/if/if chains.

Declarative, ORM-agnostic filter classes for NestJS. One decorator in your controller reads query params, validates them, dispatches to filter methods, and hands you a ready-to-execute query builder — with 22 operators, auto-fields, and a typed client-side builder for your frontend team. MikroORM and TypeORM.

4 packages on npm · 22 operators · MikroORM + TypeORM adapters

users.service.ts✗ without nestjs-filter
async findUsers(query: UserQuery) {
const qb = this.repo.createQueryBuilder('u');
if (query.name) {
qb.andWhere({ name: { $like: `%${query.name}%` } });
}
if (query.email) {
qb.andWhere({ email: query.email });
}
if (query.active !== undefined) {
qb.andWhere({ active: query.active });
}
// ...20 more fields
return qb.getResultList();
}
user.filter.ts✓ with nestjs-filter
@Filterable({ entity: User })
export class UserFilter extends MikroOrmFilter<User> {
@FilterFor()
name(v: string) {
this.whereLike('name', v);
}
@FilterFor()
status(v: string[]) {
this.whereIn('status', v);
}
}
// Controller: one line
@Get() list(@ApplyFilter(UserFilter) qb) {
return qb.getResultList();
}

Filtering as a first-class citizen

Six guarantees, one mental model. Query-string in, validated and composable query builder out.

@ApplyFilter decorator

One decorator in your controller. It reads query params (GET) or body (POST), validates with class-validator, dispatches to filter methods, and hands you back a ready-to-execute query builder.

Auto-fields

For simple equality and operator filters, skip writing methods entirely: declare autoFields with an allowlist and WHERE clauses are generated from query params automatically.

22 built-in operators

equals, contains, gte, between, in, isNull, isAnyOf and friends — composable with AND/OR logic via bracket notation, for auto-fields and custom @FilterFor methods alike.

Client-side query builder

A fluent, type-safe API for building filter queries in the browser or Node. Zero dependencies, generates the exact format the server expects. Ship it to your frontend team.

ORM-agnostic core

First-class MikroORM and TypeORM adapters over a shared core. Filter classes express intent (whereLike, whereIn); the adapter translates to your query builder.

Validated input

Filter payloads run through class-validator before any method fires. Unknown fields are rejected by the allowlist — clients only ever filter what you exposed.

equalsnotEqualscontainsiContainsnotContainsstartsWithendsWithgteltegtltbetweennotBetweeninnotInisAnyOfisNullisNotNullisEmptyisNotEmptyexistsnotExists
Same language on both ends

The frontend speaks filter too.

filterQuery() builds the exact query format the server expects — fluent, typed, zero dependencies. No more hand-assembled query strings drifting out of sync with the backend's parser.

Full setup guide
search-form.tsx
import { filterQuery } from '@dudousxd/nestjs-filter-client';
const query = filterQuery()
.contains('name', 'Al')
.gte('age', 18)
.in('status', ['active', 'pending'])
.build();
// => name[contains]=Al&age[gte]=18
// &status[in]=active,pending

Zero to filtering in under 5 minutes.

Install the core, pick your ORM adapter, write one filter class — and delete the if-chain for good.