Skip to content

safdar-azeem/graphql-prisma-postgres-ts-boilerplate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

545 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

GraphQL, Prisma, Postgres, TypeScript Boilerplate

A production-ready GraphQL API boilerplate with built-in database sharding, authentication, and Docker deployment.

πŸš€ Tech Stack

  • Runtime: Node.js v22+
  • Language: TypeScript
  • Framework: Fastify 5 + Mercurius (GraphQL)
  • Database: PostgreSQL with Prisma ORM
  • Sharding: prisma-sharding
  • Authentication: AuthLite + Refresh Token Rotation
  • Caching: Resilient Redis (Graceful Degradation)
  • Queue: BullMQ with Dashboard
  • Security: Helmet, Rate Limiting, CORS, OTP
  • Deployment: Docker + Nginx load balancer
  • Testing: Vitest

⚑ Why Fastify + Mercurius?

This boilerplate uses Fastify + Mercurius instead of Express + Apollo Server for:

Feature Fastify + Mercurius Express + Apollo
Performance πŸš€ Excellent Good
Security defaults βœ… Strong Manual setup
Schema validation βœ… Built-in Manual
Request overhead Lower Higher
Async/await Native Middleware-based

πŸƒ Quick Start

Option 1: Docker (Recommended)

git clone <repository_url>
cd graphql-prisma-postgres-ts-boilerplate
yarn docker:dev        # Start development environment (uses .env.docker)
yarn docker:migrate    # Run database migrations

Open http://localhost:3001/graphql

Option 2: Local Development

Prerequisites: Node.js v22+, PostgreSQL, Redis running locally

Note: Ensure your .env file uses localhost for DATABASE_URL and REDIS_HOST.

git clone <repository_url>
cd graphql-prisma-postgres-ts-boilerplate
yarn install
yarn db:update
yarn dev               # Start development server

πŸ›‘οΈ Security Features

This boilerplate comes hardened by default:

  • Helmet: Adds secure HTTP headers (CSP, HSTS, X-Frame-Options, etc.)
  • Rate Limiting: Hybrid IP/User-based limiting with Redis backing (1000 req/min auth, 60 req/min anon)
  • CORS: Strict origin matching (no wildcard subdomains)
  • OTP: Cryptographically secure 6-digit codes (crypto.randomInt)
  • GraphQL:
    • Query Depth: Max depth of 10 to prevent nested attacks
    • Introspection: Disabled in production (NODE_ENV=production)

πŸ” Authentication Flow

Implements a secure Access + Refresh Token strategy:

  1. Login/Signup: Returns { token, refreshToken, user }
    • token: Short-lived (15m), sent in Authorization: Bearer header
    • refreshToken: Long-lived (7d), used to get new tokens
  2. Refresh: Call refreshTokens(refreshToken) mutation to get a new pair.
    • Old refresh token is revoked (Reuse Detection).
  3. Logout: logout or logoutAll to revoke tokens.
  4. Storage: Refresh tokens are stored in Redis with whitelist for validation.

πŸ“¨ Job Queues (BullMQ)

Asynchronous tasks are handled by BullMQ on Redis.

  • Workers: Located in src/queues/*.queue.ts
  • Dashboard: Visit /admin/queues to monitor jobs (Auto-disabled in Production)
  • Resilience:
    • Automatic retries with exponential backoff
    • Dead Letter Queue (DLQ) for failed jobs
    • Graceful shutdown of workers

🧱 Resilience

  • Redis: The app starts even if Redis is down. Caching and Rate Limiting degrade gracefully to in-memory fallback.
  • Database: Circuit breakers for extensive sharding operations.

πŸ§ͺ Testing

Automated Unit Tests (Vitest)

This project uses Vitest for unit testing, focusing on GraphQL resolvers and business logic. The tests are configured with a custom reporter for clean, action-oriented output.

yarn test

Output Example:

Get user : SUCCESS
Create a new user : SUCCESS
Login user : SUCCESS
...
--- Test Summary ---
Total: 25
Passed: 25
Failed: 0

Manual GraphQL Testing

Option 1: Apollo Sandbox (Recommended)

The best GraphQL IDE experience! Open in your browser:

https://studio.apollographql.com/sandbox/explorer

Then connect to: http://localhost:4200/graphql

Option 2: Built-in GraphiQL

Open: http://localhost:4200/graphiql

Option 3: cURL

# Test introspection
curl -X POST http://localhost:4200/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __typename }"}'

# Test a query
curl -X POST http://localhost:4200/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ me { id email } }"}'

# With authentication
curl -X POST http://localhost:4200/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"query": "{ me { id email username } }"}'

Option 4: Desktop Apps


πŸ“¦ Commands

Development

Command Description
yarn dev Start local dev server with hot-reload
yarn docker:dev Start Docker dev environment
yarn docker:dev:build Rebuild and start Docker dev
yarn docker:dev:logs View Docker dev logs
yarn docker:dev:down Stop Docker dev containers

Production

Command Description
yarn build Build production bundle
yarn start Start production server
yarn docker:prod Start Docker production environment
yarn docker:prod:build Rebuild and start Docker prod
yarn docker:prod:logs View Docker prod logs
yarn docker:prod:down Stop Docker prod containers

Database

Command Description
yarn db:udpate It generates Prisma Client types and migrates all shards
yarn db:studio Open Prisma Studio for all shards
yarn test:shards Test shard connectivity
yarn docker:migrate Run migrations in Docker

Utilities

Command Description
yarn generate Generate GraphQL types
yarn docker:clean Remove all Docker volumes and images
yarn docker:sh Shell into app container

🐳 Docker Architecture

β”œβ”€β”€ Dockerfile               # Multi-stage (dev + prod stages)
β”œβ”€β”€ docker-compose.yml       # Development environment (uses .env.docker)
β”œβ”€β”€ docker-compose.prod.yml  # Production environment (uses .env)
β”œβ”€β”€ .env                     # Local/Prod Configuration
└── nginx/nginx.conf         # Load balancer

The single Dockerfile contains both development and production stages:

  • Development: target: development - hot-reload, dev dependencies
  • Production: target: production - optimized, minimal image

πŸ—„οΈ Database Sharding

Built-in horizontal sharding across multiple PostgreSQL instances:

import { getShardForUser, findUserAcrossShards } from '@/config/prisma'

// Get shard for a specific user
const client = getShardForUser(userId)
const user = await client.user.findUnique({ where: { id: userId } })

// Find user across all shards
const { result } = await findUserAcrossShards(async (client) =>
  client.user.findFirst({ where: { email: 'user@example.com' } })
)

Database performance optimization.

Use the graphql-prisma-select package to fetch only the fields required by the client. This helps resolve the over-fetching problem and improves database performance.

import { prismaSelect } from 'graphql-prisma-select'

const resolvers = {
  Query: {
    users: async (parent, args, context, info) => {
      const select = prismaSelect(info)

      // Equivalent to: prisma.user.findMany({ select: { id: true, email: true, ... } })
      return context.prisma.user.findMany({
        ...args, // pagination, filtering, etc.
        select,
      })
    },

    user: async (parent, { id }, context, info) => {
      const select = prismaSelect(info)
      return context.prisma.user.findUnique({
        where: { id },
        select,
      })
    },
  },
}

πŸ“‚ Project Structure

src/
β”œβ”€β”€ modules/           # Feature modules (auth, user, etc.)
β”‚   └── <module>/
β”‚       β”œβ”€β”€ graphql/   # GraphQL schema
β”‚       └── resolvers/ # Business logic
β”‚       └── tests/     # Unit tests
β”œβ”€β”€ config/            # Prisma, Redis, AuthLite, Tokens, Queues
β”œβ”€β”€ middleware/        # Auth, CORS, Rate Limit
β”œβ”€β”€ queues/            # BullMQ definitions & workers
β”œβ”€β”€ guards/            # Authentication guards
β”œβ”€β”€ cache/             # Redis caching strategies
β”œβ”€β”€ errors/            # Error handling & formatters
β”œβ”€β”€ graphql/           # Scalars & base schema
β”œβ”€β”€ types/             # Generated TypeScript types
β”œβ”€β”€ utils/             # Shared utilities
└── server.ts          # Fastify entry point

services/storage/      # πŸ“¦ Storage Microservice
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ providers/     # S3, Cloudinary, ImageKit, Local
β”‚   β”œβ”€β”€ services/      # File, upload, folder, share-link logic
β”‚   β”œβ”€β”€ routes/        # REST API endpoints
β”‚   └── server.ts      # Express entry point
└── README.md          # Full API reference

πŸš€ Production Deployment

VPS with GitHub Actions

This boilerplate uses dynamic project naming - your repository name becomes the project identifier, allowing multiple deployments on the same VPS without conflicts.

Setup:

  1. Run on VPS: curl -fsSL https://raw.githubusercontent.com/safdar-azeem/graphql-prisma-postgres-ts-boilerplate/main/scripts/setup-vps.sh | bash
  2. Set GitHub secrets:
    • VPS_HOST - Your VPS IP address
    • VPS_USERNAME - SSH username (usually root)
    • VPS_SSH_KEY - Private SSH key for authentication
    • GH_SECRET - GitHub Personal Access Token
  3. Push to main branch β†’ auto-deploys

See docs/5-setup-vps-deployment.md for detailed VPS setup.


πŸ› Troubleshooting

Issue Solution
Server exits immediately Check MFA_ENCRYPTION_KEY is set (32 chars)
Port already in use Kill process: lsof -i :4200 then kill -9 <PID>
Docker build fails Run yarn docker:clean and try again
Redis connection error Ensure Redis is running: redis-server
GraphiQL not loading Use Apollo Sandbox instead (see Testing section)

πŸ“š Documentation


πŸ“Š Performance

Fastify + Mercurius provides excellent performance for GraphQL applications:

  • JIT Query Compilation - Queries are compiled for faster execution
  • Automatic Loader Integration - Prevents N+1 query problems
  • Query Parsing Cache - Validated queries are cached
  • Low Request Overhead - Fastify's async architecture

For benchmarking, use:

autocannon -c30 -d10 http://localhost:4200/health

Releases

No releases published

Packages

 
 
 

Contributors

Languages