Use TypeORM with DaloyJS
TypeORM gives you decorator-based entities and the active-record / data-mapper patterns familiar to Java and .NET teams. It runs best on the Node.js adapter.
1. Install
pnpm add typeorm reflect-metadata pg
pnpm add -D @types/nodeTypeORM relies on reflect-metadata and decorator metadata. Make sure your tsconfig.json enables them:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strictPropertyInitialization": false
}
}2. Define an entity
// src/db/entities/User.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from "typeorm";
@Entity("users")
export class User {
@PrimaryGeneratedColumn("uuid")
id!: string;
@Column({ unique: true })
email!: string;
@Column({ type: "text", nullable: true })
name!: string | null;
@CreateDateColumn({ name: "created_at" })
createdAt!: Date;
}3. Configure the DataSource
// src/db/data-source.ts
import "reflect-metadata";
import { DataSource } from "typeorm";
import { User } from "./entities/User";
export const AppDataSource = new DataSource({
type: "postgres",
url: process.env.DATABASE_URL,
entities: [User],
migrations: ["src/db/migrations/*.ts"],
synchronize: false, // use migrations in production
logging: process.env.NODE_ENV !== "production",
});4. Create a TypeORM plugin
// src/db/plugin.ts
import type { App } from "@daloyjs/core";
import { AppDataSource } from "./data-source";
export const typeormPlugin = {
name: "typeorm",
async register(app: App) {
if (!AppDataSource.isInitialized) {
await AppDataSource.initialize();
}
app.decorate("db", AppDataSource);
app.onClose(async () => {
if (AppDataSource.isInitialized) await AppDataSource.destroy();
});
},
};5. Augment app state types
// src/types/state.d.ts
import type { DataSource } from "typeorm";
declare module "@daloyjs/core" {
interface AppState {
db: DataSource;
}
}6. Use repositories in routes
// src/server.ts
import "reflect-metadata";
import { z } from "zod";
import { App } from "@daloyjs/core";
import { serve } from "@daloyjs/core/node";
import { typeormPlugin } from "./db/plugin";
import { User } from "./db/entities/User";
const app = new App();
app.register(typeormPlugin);
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().nullable(),
createdAt: z.coerce.date(),
});
app.route({
method: "GET",
path: "/users/:id",
operationId: "getUser",
request: { params: z.object({ id: z.string().uuid() }) },
responses: {
200: { description: "Found", body: UserSchema },
404: { description: "Not found" },
},
handler: async ({ params, state }) => {
const repo = state.db.getRepository(User);
const user = await repo.findOneBy({ id: params.id });
return user
? { status: 200, body: user }
: { status: 404, body: { type: "about:blank", title: "Not found", status: 404 } };
},
});
app.route({
method: "POST",
path: "/users",
operationId: "createUser",
request: { body: z.object({ email: z.string().email(), name: z.string().optional() }) },
responses: { 201: { description: "Created", body: UserSchema } },
handler: async ({ body, state }) => {
const repo = state.db.getRepository(User);
const created = await repo.save(repo.create(body));
return { status: 201, body: created };
},
});
await app.ready();
serve(app, { port: 3000 });Transactions
handler: async ({ body, state }) => {
return state.db.transaction(async (manager) => {
const order = await manager.save(Order, manager.create(Order, body));
await manager.decrement(Inventory, { sku: body.sku }, "stock", body.qty);
return { status: 201, body: order };
});
}Migrations
pnpm typeorm migration:generate src/db/migrations/InitUser -d src/db/data-source.ts
pnpm typeorm migration:run -d src/db/data-source.tsRuntime notes
- TypeORM uses Node-only APIs (filesystem, native drivers). It does not run on Cloudflare Workers or Vercel Edge — use Drizzle or Supabase there.
- On Bun and Deno, prefer
drizzle-style postgres clients unless you need TypeORM's decorators. - Always import
reflect-metadataonce at the entrypoint, before anything else.
Compare with Prisma, Drizzle, Sequelize, or the ODM overview if you need document models.