Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
dist
coverage
.env
.git
.gitignore
npm-debug.log*
10 changes: 7 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
DB_URI=mongodb://localhost:27017
PORT=3000
NODE_ENV=development
HOST=localhost

PORT=3000
DB_URI=mongodb://localhost:27017/express_starter
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
LOG_LEVEL=info
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
push:
branches: [master, main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10.10.0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm test
- run: pnpm build
11 changes: 7 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
node_modules/
.env
.env.*
!.env.example
dist/

# pnpm
pnpm-lock.yaml
pnpm-workspace.yaml
coverage/
.DS_Store
npm-debug.log*
yarn-debug.log*
yarn-error.log*
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM node:22-alpine AS deps
WORKDIR /app
RUN corepack enable
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

FROM node:22-alpine AS build
WORKDIR /app
RUN corepack enable
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build
RUN pnpm prune --prod

FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S app && adduser -S app -G app
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER app
EXPOSE 3000
CMD ["node", "dist/index.js"]
139 changes: 86 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,115 @@
# Express Starter 🚀

A minimal and scalable Express + TypeScript starter project. This template helps you quickly spin up a REST API or microservice with clean architecture and modern tooling.

## ✨ Features

- Express 5 — modern middleware and routing

- TypeScript — strong typing out of the box

- Mongoose — ODM for MongoDB

- Modular structure — `controllers`, `routes`, `middlewares`, `schemas`, `utils`

- .env support — via `tsx` and `node --env-file`

- Tsc Alias — clean, short import paths

## 📂 Project Structure
A simple but strong Express 5 + TypeScript starter kit for production-minded REST APIs.

## What is included

- Express 5 application factory with dependency injection-friendly composition.
- TypeScript strict mode with path aliases and additional safety flags.
- Built-in request validation for bodies and route params.
- Centralized error handling with safe response envelopes.
- Security headers, CORS, JSON body limits, request IDs, and in-memory rate limiting.
- Structured JSON request logging.
- Feature-based users and health modules.
- Mongoose repository implementation plus an in-memory repository for tests.
- Password hashing with Node.js `crypto.scrypt` and public DTO responses that never expose password hashes.
- Liveness/readiness health checks.
- OpenAPI JSON starter endpoint.
- Node test runner API tests.
- Docker, Docker Compose, and GitHub Actions CI.
- Graceful shutdown for HTTP server and database connections.

## Project structure

```bash
src/
├── app.ts # Express app configuration
├── index.ts # Entry point (server starts here)
├── config/ # Configurations
├── controllers/ # Controllers
├── middlewares/ # Middlewares
├── routes/ # Routes
├── schemas/ # Mongoose schemas
└── utils/ # Helpers and types
├── app.ts # Express app factory
├── index.ts # Infrastructure bootstrap and graceful shutdown
├── config/ # Environment validation and logger
├── infrastructure/database/ # Mongoose connection lifecycle
├── modules/
│ ├── health/ # Liveness/readiness routes
│ ├── openapi/ # OpenAPI JSON endpoint
│ └── users/ # User feature module
└── shared/
├── errors/ # Application error types
├── http/ # Request lifecycle utilities
└── middleware/ # Shared middleware
```

## 🛠️ Installation
```bash
# Clone the repository
git clone https://github.com/xteam-uz/express-starter.git
cd express-starter
## Requirements

# Install dependencies (recommended PNPM)
pnpm install
```
- Node.js 22+
- PNPM 10+
- MongoDB for database-backed routes

## ⚙️ Configuration
## Setup

Create a .env file in the project root:
```bash
SERVER_HOST=localhost
SERVER_PORT=3000
DB_URI=mongodb://localhost:27017/
pnpm install
cp .env.example .env
pnpm dev
```

## 🚀 Run
## Configuration

Environment variables are validated at startup.

Development:
```bash
pnpm dev
NODE_ENV=development
HOST=localhost
PORT=3000
DB_URI=mongodb://localhost:27017/express_starter
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
LOG_LEVEL=info
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100
```
Runs with hot-reload using tsx.

## Build:
## Scripts

```bash
pnpm build
pnpm dev # Run with hot reload
pnpm build # Compile TypeScript and rewrite path aliases
pnpm start # Run compiled application
pnpm typecheck # Type-check without emitting files
pnpm lint # Run TypeScript lint-style checks
pnpm test # Run API tests
```

## Production:
## API endpoints

```bash
pnpm start
GET /health/live
GET /health/ready
GET /docs/openapi.json
GET /api/users
GET /api/users/:id
POST /api/users
PUT /api/users/:id
DELETE /api/users/:id
```

## 📡 Example API
## Docker

src/routes/user.ts defines routes handled by UserController:
```bash
GET /users
POST /users
docker compose up --build
```
The Mongoose schema is defined in src/schemas/user.schema.ts.

## 🧑‍💻 Contributing
The API listens on `http://localhost:3000` and MongoDB on `localhost:27017`.

## Security baseline

This starter intentionally includes a minimal security baseline instead of leaving it as an exercise:

- Built-in middleware disables or hardens common HTTP headers.
- CORS is environment-driven instead of wide open by default.
- JSON payloads are capped at `100kb`.
- Rate limiting is enabled globally.
- Passwords are hashed before storage.
- Password hashes are excluded from public responses.
- Error responses avoid leaking raw exception objects.

Feel free to open an issue or submit a pull request to improve this project.
## Architecture notes

The application uses feature modules and constructor-injected services/repositories so that controllers stay thin and tests can run without MongoDB. This keeps the starter simple while leaving room for Clean Architecture or Hexagonal Architecture evolution.
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
services:
api:
build: .
environment:
NODE_ENV: production
HOST: 0.0.0.0
PORT: 3000
DB_URI: mongodb://mongo:27017/express_starter
CORS_ORIGINS: http://localhost:3000
ports:
- "3000:3000"
depends_on:
- mongo

mongo:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db

volumes:
mongo_data:
Loading
Loading