Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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