Skip to content

Relayer

Type-safe repository layer that sits between your ORM and your API. Computed fields, derived fields, Prisma-like query DSL, and framework integrations for Next.js and NestJS.

Why Relayer?

Relayer makes dynamic fields (computed, derived, JSON) a first-class part of your data model — filterable, sortable, selectable, and aggregatable on equal terms with regular columns. Not through raw SQL escape hatches, but as a core design principle. The query DSL is a plain JSON-serializable object, ready to wire up as REST or GraphQL filters.

Currently ships with a Drizzle ORM adapter. Adapters for Kysely, TypeORM, and other ORMs are planned.

Core Features

First-Class Dynamic Fields

Computed, derived, and JSON fields are type-safe, filterable, sortable, and selectable — treated equally to regular columns.

Complex Filtering

AND, OR, NOT, relation filters (some, every, none), custom SQL in where, 20+ operators. All as a JSON-serializable DSL.

Relations

Batch loading without N+1, per-relation row limits, connect/disconnect/set for managing relations in mutations.

Aggregations

_count, _sum, _avg, _min, _max with groupBy and having. Full support for computed, derived, and JSON fields.

Type-Safe Autocomplete

Full inference for own fields, nested relations, and even nested derived fields across entities.

Multi-Dialect

PostgreSQL, MySQL, SQLite with dialect-aware optimizations for ILIKE, array operators, JSON paths, RETURNING.

Framework Integrations

Next.js

Type-safe App Router route handlers with validation, lifecycle hooks, SSR direct calls, and configurable field whitelists. Learn more →

NestJS REST

Full-featured REST CRUD with DI-native services, lifecycle hooks, DTO mapping, complex filters, pagination, and Swagger auto-docs. Learn more →

NestJS GraphQL

Code-first GraphQL CRUD with auto-generated schemas, dual pagination, rich filtering, and lifecycle hooks. One decorator, full API. Learn more →

Packages

PackageDescription
@relayerjs/drizzleDrizzle ORM adapter — main package
@relayerjs/coreORM-agnostic types and contracts
@relayerjs/nextNext.js App Router CRUD integration
@relayerjs/nestjs-crudNestJS CRUD controllers with DI, hooks, Swagger
@relayerjs/nestjs-graphqlNestJS GraphQL code-first CRUD with filtering and pagination

Quick Example

import { createRelayerDrizzle, createRelayerEntity } from '@relayerjs/drizzle';
import * as schema from './schema'; // your Drizzle schema
// Entity model with computed and derived fields
const UserEntity = createRelayerEntity(schema, 'users');
class User extends UserEntity {
@UserEntity.computed({
resolve: ({ table, sql }) => sql`upper(${table.name})`,
})
displayName!: string;
@UserEntity.derived({
query: ({ db, schema: s, sql, field }) =>
db
.select({ [field()]: sql<number>`count(*)::int`, authorId: s.posts.authorId })
.from(s.posts)
.groupBy(s.posts.authorId),
on: ({ parent, derived, eq }) => eq(parent.id, derived.authorId),
})
postsCount!: number;
}
const r = createRelayerDrizzle({ db, schema, entities: { users: User } });
// Query: everything is fully type-safe
const result = await r.users.findMany({
select: {
id: true,
displayName: true,
postsCount: true,
posts: { $limit: 5, id: true, title: true },
},
where: {
metadata: { role: 'admin' },
posts: { some: { title: { contains: 'Relayer' } } },
},
orderBy: { field: 'postsCount', order: 'desc' },
limit: 10,
});
// Aggregation with full computed/derived/JSON support
const stats = await r.posts.aggregate({
groupBy: ['author.name'],
_count: true,
_max: { title: true },
});