{"id":19227452,"url":"https://github.com/sushantrahate/express-typescript-prisma-postgresql","last_synced_at":"2025-09-10T09:32:07.172Z","repository":{"id":200505731,"uuid":"703917009","full_name":"sushantrahate/express-typescript-prisma-postgresql","owner":"sushantrahate","description":"For building RESTful APIs using Express, TypeScript, Prisma, and PostgreSQL.","archived":false,"fork":false,"pushed_at":"2024-11-24T14:59:42.000Z","size":832,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-24T15:33:59.069Z","etag":null,"topics":["eslint","express","nodejs","postgresql","prisma","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sushantrahate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-12T07:12:34.000Z","updated_at":"2024-11-24T14:59:45.000Z","dependencies_parsed_at":"2023-10-17T04:22:13.011Z","dependency_job_id":"8b7ebe54-5b8e-40d7-9b96-1cfda93c01cb","html_url":"https://github.com/sushantrahate/express-typescript-prisma-postgresql","commit_stats":null,"previous_names":["sushantrahate/express-typescript-prisma-postgresql"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushantrahate%2Fexpress-typescript-prisma-postgresql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushantrahate%2Fexpress-typescript-prisma-postgresql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushantrahate%2Fexpress-typescript-prisma-postgresql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushantrahate%2Fexpress-typescript-prisma-postgresql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sushantrahate","download_url":"https://codeload.github.com/sushantrahate/express-typescript-prisma-postgresql/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232525269,"owners_count":18536902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eslint","express","nodejs","postgresql","prisma","typescript"],"created_at":"2024-11-09T15:23:23.591Z","updated_at":"2025-09-10T09:32:07.160Z","avatar_url":"https://github.com/sushantrahate.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🚀 Express + TypeScript + Prisma + PostgreSQL Boilerplate (2025 Edition)\n\nThis is a backend built with Node.js, Express, TypeScript, and Prisma ORM. It follows modern best practices for API development, including strict type safety, structured error handling, security measures, and environment validation.\n\nDesigned to be modular and maintainable, the project features a clean architecture, making it easy to extend with new functionalities.\n\n## ✨ Features\n\n🛠️ Core Features\\\n✅ TypeScript – Fully typed backend for maintainability\\\n✅ Express.js – Lightweight and fast web framework\\\n✅ Prisma ORM – Type-safe database interactions\n✅ PostgreSQL – Relational database\\\n\\\n🎯 Development \u0026 Code Quality\\\n✅ Feature-Based Structure – Each feature has its own folder, keeping everything related to a feature (routes, schemas, types, services, controllers, repositories) together for better maintainability and scalability\\\n✅ ESLint + Prettier – Code linting, formatting and autoformat on save\\\n✅ Zod Validation – Strict schema validation for request \u0026 environment variables\\\n✅ VSCode debugger\\\n\\\n🔐 Environment \u0026 Security\\\n✅ Environment Validation – Ensures required .env variables exist\\\n✅ Helmet \u0026 Security Headers – Protects against web vulnerabilities\\\n✅ Rate Limiter, Host whitelisting middleware\\\n\\\n⚡ API \u0026 Middleware\\\n✅ Request Validation – Uses Zod for body, params, and query validation\\\n✅ Error Handling Middleware – Centralized error handling with PostgreSQL error handling [(Ref)](https://www.prisma.io/docs/orm/reference/error-reference)\\\n✅ Unified Response Structure – Uses [uni-response](https://github.com/sushantrahate/uni-response) for consistent API responses\\\n\\\n🧪 Testing \u0026 CI/CD\\\n✅ Vitest – Unit and integration testing\\\n✅ Husky + Lint-Staged – Enforces pre-commit linting and testing\\\n\\\n🛑 Server Management\\\n✅ Graceful Shutdown – Ensures proper cleanup of database \u0026 open connections during shutdown [(Ref)](https://github.com/sushantrahate/secure-nodejs-backend/tree/main/graceful-shutdown)\n\n## 🛠️ Clean Architecture \u0026 Feature-Based Structure\n\n### 📌 Clean Architecture \u0026 Framework-Agnostic Design\n\nThis project follows a feature-based modular structure, where each feature (e.g., user) has its own isolated folder containing everything related to that feature.\n\n📂 Project Structure:\n\n```bash\nsrc/\n│── config/         # Configuration (e.g., environment variables, Prisma, security)\n│── constants/      # Shared constants (messages, enums, etc.)\n│── features/       # Feature-based modular structure\n│   ├── user/       # User feature module\n│   │   ├── __tests__/      # Unit tests (vitest)\n│   │   ├── controllers/    # Handles HTTP requests (Express-dependent)\n│   │   ├── repositories/   # Database interactions (Prisma-dependent)\n│   │   ├── routes/         # Express API routes (Express-dependent)\n│   │   ├── schemas/        # Zod validation schemas (Framework-agnostic)\n│   │   ├── services/       # Business logic (Completely framework-independent)\n│   │   ├── types/          # TypeScript interfaces \u0026 types\n│── middleware/      # Global Express middlewares\n│── utils/           # Helper functions\n│── app.ts           # Express app setup\n│── server.ts        # Entry point\n```\n### 📌 Layer-by-Layer Breakdown\n\n### 1️⃣ Feature Modules (e.g., user/)\n\nEach feature is self-contained, meaning everything related to \"users\" is inside `features/user/`\n\n🎯 Benefit:\\\n💡 You can easily add or remove features without affecting other parts of the app.\n\n🔹 **No Cluttering, Even as the Project Grows Large –** The feature-based structure ensures that related files stay together, preventing scattered code.\\\n🔹 **Everything in One Place –** Developers can find all logic related to a feature (controllers, services, repositories, schemas) in a single folder, reducing confusion.\\\n🔹 **No Ambiguity in Large Systems –** Since each feature is self-contained, developers always know which controller, service, or repository to use, making onboarding and scaling easier.\\\n🔹 **Scalability \u0026 Maintainability –** Adding a new feature means simply creating a new folder under features/, without modifying unrelated parts of the app.\n\n### 2️⃣ Controllers (controllers/)\n\n✅ Handles HTTP requests and responses\\\n✅ Calls the service layer for business logic\\\n✅ Only responsible for Express-specific logic\n\n📄 Example: user.controller.ts\n\n```ts\nimport { Request, Response } from \"express\";\nimport { UserService } from \"../services/user.service\";\n\nexport class UserController {\n  private userService: UserService;\n\n  constructor() {\n    this.userService = new UserService();\n  }\n\n  async getUsers(req: Request, res: Response) {\n    const users = await this.userService.getAllUsers();\n    res.json({ success: true, data: users });\n  }\n}\n```\n\n### 🛠️ Why This Structure?\\\n\nExpress-specific logic stays here (e.g., req, res)\\\nBusiness logic is in the service layer (so it’s framework-agnostic)\n\n🎯 Benefit:\\\n💡 Can switch from Express to Fastify/NestJS by just changing the controllers.\n\n### 3️⃣ Services (services/)\n\n✅ Contains core business logic\\\n✅ Does NOT depend on Express or Prisma\\\n✅ Interacts with repositories for data retrieval\\\n\n📄 Example: user.service.ts\n\n```ts\nimport { UserRepository } from \"../repositories/user.repository\";\n\nexport class UserService {\n  private userRepository: UserRepository;\n\n  constructor() {\n    this.userRepository = new UserRepository();\n  }\n\n  async getAllUsers() {\n    return await this.userRepository.getUsers();\n  }\n}\n```\n\n### 🛠️ Why This Structure?\n\n- No dependency on Express or HTTP requests\n- Calls repository for database access\n\n🎯 Benefit:\\\n💡 Can be reused in a CLI app, background worker, or GraphQL API without changes.\n\n\n### 4️⃣ Repositories (repositories/)\n\n✅ Handles all database queries\\\n✅ Uses Prisma (or any ORM, easily replaceable)\\\n✅ Interacts only with services/, never controllers\n\n📄 Example: user.repository.ts\n\n```ts\nimport { prisma } from \"@/config/prisma.config\";\n\nexport class UserRepository {\n  async getUsers() {\n    return await prisma.user.findMany();\n  }\n}\n```\n\n### 🛠️ Why This Structure?\n\n- Keeps database logic separate from business logic\n- Easy to swap Prisma for another ORM (e.g., Drizzle, TypeORM)\n\n🎯 Benefit:\\\n💡 Can change the database or ORM without affecting services/controllers.\n\n### 5️⃣ Routes (routes/)\n\n✅ Defines API endpoints\\\n✅ Maps controllers to Express routes\n\n📄 Example: user.routes.ts\n\n```ts\nimport { Router } from \"express\";\nimport { UserController } from \"../controllers/user.controller\";\n\nconst router = Router();\nconst userController = new UserController();\n\nrouter.get(\"/\", (req, res) =\u003e userController.getUsers(req, res));\n\nexport default router;\n```\n\n### 🛠️ Why This Structure?\n\n- Controllers are injected into routes for better testability\n- Only Express-dependent part is here\n\n🎯 Benefit:\\\n💡 Can switch to NestJS, Fastify, or Hono by only changing routes \u0026 controllers.\n\n### 6️⃣ Validation Schemas (schemas/)\n\n✅ Uses Zod for request validation\n✅ Completely framework-independent\n\n📄 Example: user.schema.ts\n\n```ts\nimport { z } from \"zod\";\n\nexport const createUserSchema = z.object({\n  email: z.string().email(),\n  name: z.string().optional(),\n});\n```\n\n### 🛠️ Why This Structure?\n\n- Schemas don’t depend on Express, so they can be used anywhere\n- Validation logic is reusable (can be used in GraphQL, CLI, or workers)\n- \n🎯 Benefit:\\\n💡 Easier to enforce validation rules across different application layers.\n\n### 🛠️ Final Benefits Summary\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eLayer\u003c/th\u003e\n      \u003cth\u003ePurpose\u003c/th\u003e\n      \u003cth\u003eBenefit\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cstrong\u003eControllers\u003c/strong\u003e\u003c/td\u003e\n      \u003ctd\u003eHandle HTTP requests\u003c/td\u003e\n      \u003ctd\u003eFramework-dependent, easily replaceable\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cstrong\u003eServices\u003c/strong\u003e\u003c/td\u003e\n      \u003ctd\u003eBusiness logic\u003c/td\u003e\n      \u003ctd\u003eFramework-agnostic, reusable anywhere\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cstrong\u003eRepositories\u003c/strong\u003e\u003c/td\u003e\n      \u003ctd\u003eDatabase interactions\u003c/td\u003e\n      \u003ctd\u003eCan switch ORM (Prisma, TypeORM, Drizzle)\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cstrong\u003eRoutes\u003c/strong\u003e\u003c/td\u003e\n      \u003ctd\u003eMaps controllers to APIs\u003c/td\u003e\n      \u003ctd\u003eOnly responsible for Express routing\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cstrong\u003eSchemas\u003c/strong\u003e\u003c/td\u003e\n      \u003ctd\u003eData validation\u003c/td\u003e\n      \u003ctd\u003eReusable validation logic across app\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n## ✨ Setup from scratch\n\n## ⚡ TypeScript \u0026 Development Dependencies Setup\n\n```bash\nmkdir express-ts-prisma \u0026\u0026 cd express-ts-prisma\nnpm init -y\n```\n\n```bash\nnpm install --save-dev typescript tsx nodemon @types/node tsc-alias\n```\n\n\u003e Create `tsconfig.json`\n\n## ⚡ Add Express, CORS, and .env Setup\n\n```bash\nnpm install express cors dotenv\nnpm install --save-dev @types/express @types/cors\n```\n\n\u003e Create `.env.dev` File from `.env.example`\n\u003e Create src/config/env-config.ts // Env Configuration file\n\u003e Create src/config/env-schema.ts // Schema for environment variables\n\n## ⚡ ESLint, Prettier \u0026 Linting Plugins\n\n```bash\nnpm install --save-dev eslint prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-prettier eslint-plugin-node eslint-plugin-import eslint-plugin-simple-import-sort eslint-plugin-unicorn eslint-plugin-security eslint-config-prettier\n```\n\n\u003e Create `eslint.config.js`\n\n\u003e Create `.prettierrc.json`\n\n\u003e Create `.prettierignore`\n\n📌 Prettier will ignore these files \u0026 folders (same format as `.gitignore`).\n\n\u003e create `.vscode/settings.json` to Autoformat using Prettier on save\n\n## ⚡ Setup Prisma \u0026 PostgreSQL\n\n\u003e Create Database and Shadow Database\n\n\u003e Update `.env.dev` File\n\n```ini\nDATABASE_URL=\"postgresql://dev_user:dev_password@localhost:5432/dev_db\"\nSHADOW_DATABASE_URL=\"postgresql://dev_user:dev_password@localhost:5432/dev_db_shadow\"\n```\n\n### Install Prisma\n\n```bash\nnpm install @prisma/client\nnpm install --save-dev prisma\n```\n\n### Initialize Prisma\n\n```bash\nnpx prisma init\n```\n\n### Modify prisma/schema.prisma\n\n```js\nmodel User {\n  id        String   @id @default(uuid())\n  email     String   @unique\n  name      String?\n  createdAt DateTime @default(now())\n}\n```\n\n### Run Migrations\n\n```bash\nnpx prisma generate\nnpx prisma migrate dev --name init\n```\n\n## ⚡ Create Express Server\n\n### Create `src/server.ts`\n\n## ⚡ Setup Husky + Lint-Staged\n\n```bash\nnpm install --save-dev husky lint-staged\n```\n\n### Enable Husky\n\n```bash\nnpx husky install\nnpm set-script prepare \"husky install\"\n```\n\n### Add Pre-commit Hook\n\n```bash\nnpx husky add .husky/pre-commit \"npx lint-staged\"\n```\n\nModify `package.json`\n\n```json\n// Runs linters (ESLint, Prettier) only on changed files before committing.\n\"lint-staged\": {\n   \"**/*.{ts,json,md}\": [\"eslint --fix\", \"prettier --write\"]\n}\n```\n\nAdd Pre-Push Hook\n\n```sh\n// Before git push trigger tests \u0026 build validation.\nnpx husky add .husky/pre-push \"npm run lint \u0026\u0026 npm run format \u0026\u0026 npm run test \u0026\u0026 npm run build\"\n```\n\n## ⚡ Add Scripts in package.json\n\n```json\n\"scripts\": {\n    \"prebuild\": \"npm run lint \u0026\u0026 npm run format \u0026\u0026 npm run test\",\n    \"build\": \"tsc\",\n    \"start\": \"node dist/server.js\",\n    \"dev\": \"nodemon --ext ts --exec tsx src/server.ts\",\n    \"lint\": \"eslint . --ext .ts\",\n    \"lint:fix\": \"eslint . --ext ts --fix\",\n    \"format\": \"prettier --write .\",\n    \"test\": \"vitest\",\n    \"prepare\": \"npx husky install\"\n  }\n```\n\n## ⚡ Run the Project\n\n```bash\n# Start Dev Server\nnpm run dev\n\n# Lint Code\nnpm run lint\nnpm run lint:fix\n\n# Format Code\nnpm run format\n```\n\n## ⚡ Vitest for Unit Testing\n\n```bash\nnpm install --save-dev vitest @vitest/coverage-v8 @types/jest supertest @types/supertest\n```\n\nCreate test files at `src\\features\\user\\__tests__`\n\n## ⚡ Security\n\n```sh\nnpm i helmet express-rate-limit\n```\n\n## ⚡ Logger\n\n```bash\nnpm install pino pino-pretty pino-http\nnpm install -D @types/pino @types/pino-pretty @types/pino-http\n```\n\nCreate src\\middleware\\pino-logger.ts\n\n## ⚡ Constants\n\n## ⚡ Middleware\n\n## ⚡ Utils\n\nIf you liked it then please show your love by ⭐ the repo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsushantrahate%2Fexpress-typescript-prisma-postgresql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsushantrahate%2Fexpress-typescript-prisma-postgresql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsushantrahate%2Fexpress-typescript-prisma-postgresql/lists"}