ORM Mongoose Overview
Mongoose structure in create-light-stack.
Directory Structure
packages/database/
├── src/
│ ├── db.ts
│ ├── index.ts
│ └── models/
│ └── example.model.ts
├── .env
├── package.json
└── tsconfig.json Connection To Api
connectDB is exported to api to connect.
It takes DATABASE_URL from .env.
import mongoose from "mongoose";
import "dotenv/config";
let isConnected = false;
export const connectDB = async () => {
if (isConnected) {
console.log("Using existing MongoDB connection");
return;
}
const url = process.env.DATABASE_URL;
if (!url) {
throw new Error("DATABASE_URL");
}
try {
await mongoose.connect(url, {
dbName: "light_stack",
});
isConnected = true;
console.log("MongoDB connected");
} catch (error) {
console.error(" MongoDB connection error:", error);
process.exit(1);
}
};
export const db = {
connect: connectDB,
client: mongoose.connection,
};Defining Models
In Light Stack, we use a "Zod-First" approach. We define the validation rules first, then infer the TypeScript types, and finally create the Mongoose schema.
Zod ensures request validation matches your model shape.
// packages/database/src/models/example.model.ts
import mongoose, { Schema } from "mongoose";
import { z } from "zod";
// Zod Schema (define schema here)
export const insertExampleSchema = z.object({
title: z.string().min(1).max(100),
description: z.string().optional(),
});
// Ts inference
export type ExampleType = z.infer<typeof insertExampleSchema>;
// Mongoose Schema
const ExampleSchema = new Schema<ExampleType>(
{
title: { type: String, required: true },
description: { type: String },
},
{
timestamps: true,
toJSON: {
transform: (_, ret) => {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
},
},
},
);
export const example = mongoose.model<ExampleType>("Example", ExampleSchema);Exporting the Schema
Make sure to export your new model in packages/database/src/index.ts.
// packages/database/src/index.ts
export * from "./models/example.model.js";