ProvenPin Install

NestJS 12 + TypeORM 1 on in-memory SQLite, tested with @nestjs/testing: working versions (tested 2026-10-15)

A NestJS module with a TypeORM entity, repository-backed service and controller, wired to in-memory SQLite and tested end to end through the Nest app with supertest. better-sqlite3 stays on 12.x because TypeORM 1.1 peers on ^12.

passed2 passed · 0 failed2026-10-15 13:31 UTC
Status
passed
Last passed
2026-10-15 13:31 UTC
Tests
2 / 2
Language
TypeScript
Runtime
node v22.23.3
pinned versions14
@nestjs/core@12.1.3@nestjs/common@12.1.3@nestjs/platform-express@12.1.3@nestjs/typeorm@12.0.2typeorm@1.1.2better-sqlite3@12.11.1reflect-metadata@0.2.2rxjs@7.8.2tsx@4.23.15@types/node@24.19.2@nestjs/testing@12.1.3supertest@7.3.1@types/supertest@7.2.1@types/express@5.0.6
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38742087302

The code

Exactly the files that passed. Your agent can pull them with get_recipe("nestjs-typeorm-sqlite") (install), or see them on GitHub.

package.json
{
  "name": "nestjs-typeorm-sqlite",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "@nestjs/core": "12.1.3",
    "@nestjs/common": "12.1.3",
    "@nestjs/platform-express": "12.1.3",
    "@nestjs/typeorm": "12.0.2",
    "typeorm": "1.1.2",
    "better-sqlite3": "12.11.1",
    "reflect-metadata": "0.2.2",
    "rxjs": "7.8.2"
  },
  "devDependencies": {
    "tsx": "4.23.15",
    "@types/node": "24.19.2",
    "@nestjs/testing": "12.1.3",
    "supertest": "7.3.1",
    "@types/supertest": "7.2.1",
    "@types/express": "5.0.6"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true
  }
}
src/app.ts
import "reflect-metadata";
import { Body, Controller, Get, Inject, Injectable, Module, NotFoundException, Param, ParseIntPipe, Post } from "@nestjs/common";
import { TypeOrmModule, getRepositoryToken } from "@nestjs/typeorm";
import { Column, Entity, PrimaryGeneratedColumn, type Repository } from "typeorm";

// Explicit column types and @Inject tokens: tsx/esbuild do not emit decorator metadata.
@Entity()
export class Todo {
  @PrimaryGeneratedColumn("increment") id!: number;
  @Column({ type: "varchar", length: 200 }) title!: string;
  @Column({ type: "boolean", default: false }) done!: boolean;
}

@Injectable()
export class TodosService {
  constructor(@Inject(getRepositoryToken(Todo)) private readonly repo: Repository<Todo>) {}
  create(title: string) { return this.repo.save(this.repo.create({ title })); }
  findAll() { return this.repo.find({ order: { id: "ASC" } }); }
  async findOne(id: number) {
    const t = await this.repo.findOneBy({ id });
    if (!t) throw new NotFoundException(`todo ${id} not found`);
    return t;
  }
}

@Controller("todos")
export class TodosController {
  constructor(@Inject(TodosService) private readonly todos: TodosService) {}
  @Post() create(@Body() body: { title: string }) { return this.todos.create(body.title); }
  @Get() all() { return this.todos.findAll(); }
  @Get(":id") one(@Param("id", ParseIntPipe) id: number) { return this.todos.findOne(id); }
}

@Module({
  imports: [
    TypeOrmModule.forRoot({ type: "better-sqlite3", database: ":memory:", entities: [Todo], synchronize: true }),
    TypeOrmModule.forFeature([Todo]),
  ],
  controllers: [TodosController],
  providers: [TodosService],
})
export class AppModule {}
test/app.test.ts
import "reflect-metadata";
import { test, before, after } from "node:test";
import assert from "node:assert/strict";
import { Test } from "@nestjs/testing";
import type { INestApplication } from "@nestjs/common";
import request from "supertest";
import { AppModule } from "../src/app.ts";

let app: INestApplication;
before(async () => {
  const mod = await Test.createTestingModule({ imports: [AppModule] }).compile();
  app = mod.createNestApplication();
  await app.init();
});
after(() => app.close());

test("create and list", async () => {
  const c = await request(app.getHttpServer()).post("/todos").send({ title: "ship" });
  assert.equal(c.status, 201);
  assert.equal(c.body.done, false);
  assert.equal((await request(app.getHttpServer()).get("/todos")).body.length, 1);
});

test("404 and pipe validation", async () => {
  assert.equal((await request(app.getHttpServer()).get("/todos/99")).status, 404);
  assert.equal((await request(app.getHttpServer()).get("/todos/abc")).status, 400);
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.