A production-ready TypeScript Express API template with JWT authentication, Supabase database, AWS S3 storage, comprehensive error handling, logging, validation, and security features.
- TypeScript - Full type safety and modern JavaScript features
- JWT Authentication - Secure token-based authentication
- Supabase - PostgreSQL database with type-safe queries
- AWS S3 - File storage integration
- Versioned Routes -
/api/v1/*structure for easy API versioning - Zod Validation - Request validation with detailed error messages
- Pino Logging - Structured JSON logging with request correlation
- Error Handling - Centralized error handling with custom error classes
- Security - Helmet, CORS, rate limiting, and request size limits
- Production Ready - Environment validation, graceful shutdown, health checks
api_template/
├── src/
│ ├── config/ # Configuration files (env, database, AWS, logger)
│ ├── middleware/ # Express middleware (auth, errors, validation, etc.)
│ ├── routes/ # API routes (versioned)
│ ├── controllers/ # Request handlers
│ ├── services/ # Business logic
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions (errors, responses)
│ ├── app.ts # Express app setup
│ └── server.ts # Server entry point
├── .env.example # Environment variables template
└── package.json
- Node.js 18+ and npm
- Supabase account and project
- AWS account with S3 bucket
- JWT secret (minimum 32 characters)
- Clone or copy this template
- Install dependencies:
npm install- Copy
.env.exampleto.envand fill in your configuration:
cp .env.example .env- Update
.envwith your actual values:JWT_SECRET: A secure random string (minimum 32 characters)SUPABASE_URL: Your Supabase project URLSUPABASE_SERVICE_ROLE_KEY: Your Supabase service role keyAWS_*: Your AWS credentials and S3 bucket name
Create a users table in your Supabase database:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);Development:
npm run devProduction:
npm run build
npm startThe API will be available at http://localhost:3000
GET /health- Basic health checkGET /api/v1/health- Detailed health check with uptime
GET /api/v1/users- Get all users (with pagination)GET /api/v1/users/:id- Get user by IDPOST /api/v1/users- Create new userPUT /api/v1/users/:id- Update userDELETE /api/v1/users/:id- Delete user
All protected routes require a JWT token in the Authorization header:
Authorization: Bearer <your-jwt-token>
The JWT token should contain at minimum a userId field in the payload.
| Variable | Description | Required | Default |
|---|---|---|---|
NODE_ENV |
Environment (development/production/test) | No | development |
PORT |
Server port | No | 3000 |
JWT_SECRET |
Secret key for JWT signing/verification | Yes | - |
JWT_EXPIRES_IN |
JWT expiration time | No | 7d |
SUPABASE_URL |
Supabase project URL | Yes | - |
SUPABASE_SERVICE_ROLE_KEY |
Supabase service role key | Yes | - |
AWS_REGION |
AWS region | No | us-east-1 |
AWS_ACCESS_KEY_ID |
AWS access key ID | Yes | - |
AWS_SECRET_ACCESS_KEY |
AWS secret access key | Yes | - |
AWS_S3_BUCKET |
S3 bucket name | Yes | - |
LOG_LEVEL |
Logging level (error/warn/info/debug) | No | info |
CORS_ORIGIN |
CORS allowed origins (comma-separated or *) | No | * |
RATE_LIMIT_WINDOW_MS |
Rate limit window in milliseconds | No | 900000 |
RATE_LIMIT_MAX_REQUESTS |
Max requests per window | No | 100 |
npm run dev- Start development server with hot reloadnpm run build- Build TypeScript to JavaScriptnpm start- Start production servernpm run lint- Run ESLintnpm run lint:fix- Fix ESLint errorsnpm run format- Format code with Prettiernpm run type-check- Type check without building
The API uses a standardized error response format:
{
"success": false,
"error": {
"message": "Error message",
"code": "ERROR_CODE",
"errors": [
{
"field": "email",
"message": "Invalid email format"
}
]
},
"requestId": "uuid",
"timestamp": "2024-01-01T00:00:00.000Z"
}Logs are structured JSON in production and pretty-printed in development. Each request includes a requestId for correlation.
- Helmet - Security headers
- CORS - Configurable cross-origin resource sharing
- Rate Limiting - Configurable request rate limits
- Request Size Limits - 10MB maximum request size
- Input Validation - All inputs validated with Zod schemas
- JWT Verification - Secure token verification
- Follow the existing code structure
- Use TypeScript strict mode
- Add validation for all inputs
- Include error handling
- Add logging for important operations
- Update this README if adding new features
MIT