Skip to content

About

Opionated boilerplate to build Fullstack TypeScript web apps

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Fullstack TypeScript Monorepo Boilerplate

An opinionated, production-ready boilerplate for building fullstack TypeScript applications with clear separation between backend and frontend. This template includes everything you need to start building a modern web application with best practices baked in.

Warning

This is intended solely for my own use. There are many problems and quirks that I'm well aware of, but I will not go into detail about them. This setup will likely not make sense to you. But feel free to fork and make it your own.

Features

Monorepo Architecture

  • pnpm workspaces for efficient dependency management
  • Turborepo for fast, cached builds
  • Clear separation: apps/ for applications, libs/ for shared code
  • Support for multiple apps in the same repository

Backend (Express + TypeScript + GraphQL)

  • Express.js with TypeScript and ESM modules
  • Dependency injection pattern with ApplicationContext
  • Multi-source configuration system (YAML files + environment variables)
  • Schema validation with Zod
  • Winston logger with JSON/text formats and rotating file support
  • Graceful shutdown handling
  • File system abstraction for testability
  • GraphQL API with GraphQL Yoga
  • WebSocket support for GraphQL subscriptions
  • Type-safe resolvers via GraphQL Code Generator
  • Modular GraphQL architecture with graphql-modules
  • Drizzle ORM for type-safe database operations
  • PostgreSQL database via postgres driver
  • Database migrations via Drizzle Kit
  • Header-based authentication middleware
  • Log streaming via GraphQL subscription
  • Frontend static file serving (optional)

Redis & Job Queues

  • Redis integration via BullMQ for background job processing
  • Abstract queue and worker base classes for easy extension
  • Bull Board UI for queue monitoring and management
  • Configurable queues and workers per instance

Frontend (React + Vite + GraphQL)

  • React 19 with React Router v7
  • Vite for lightning-fast builds and HMR
  • Tailwind CSS v4 (via @tailwindcss/vite plugin)
  • shadcn/ui component library pre-configured
  • PWA support with Workbox caching strategies
  • Dark mode support via next-themes
  • Sonner for toast notifications
  • TanStack Form for type-safe forms
  • Apollo Client for GraphQL queries, mutations, and subscriptions
  • gql.tada for compile-time type-safe GraphQL operations
  • Full TypeScript integration with generated schema types

Docker Support

  • Multi-stage Dockerfile for optimized images
  • Multi-architecture builds (ARM64 + AMD64)
  • Separate builds for backend and frontend
  • Production-ready with health checks

Code Quality

  • Biome for lightning-fast linting and formatting
  • Pre-commit hooks with Lefthook
  • Consistent code style enforced across the monorepo
  • TypeScript strict mode enabled

CI/CD

  • GitHub Actions workflows included
  • Automated linting, testing, and building
  • Docker image publishing for develop and latest tags
  • Multi-architecture Docker builds

Developer Experience

  • TypeScript path aliases (@/ for imports), resolved in the server build via tsc-alias
  • Watch modes for development
  • Fast builds with caching
  • Comprehensive npm scripts for common tasks

Using This Template

1. Create Your Repository from This Template

On GitHub:

  1. Click the "Use this template" button at the top of this repository
  2. Choose "Create a new repository"
  3. Name your repository and set visibility (public/private)
  4. Click "Create repository from template"

Or via GitHub CLI:

gh repo create my-app --private --clone --template KennethWussmann/boilerplate-fullstack-typescript
cd my-app

2a. Customize for Your Project using an AI agent (automated)

This repository ships Agent Skills in .agents/skills/, which any compatible coding agent picks up automatically. The project-bootstrap skill guides you through the entire customization of your new project.

  1. Open your coding agent in your new repository
  2. Ask it to bootstrap the project
  3. Reply to its questions
  4. Wait... Done!

You are now ready. Skip the next 2b. section.

The other bundled skills cover day-to-day work: backend-development for entities, repositories, services and GraphQL modules, frontend-development for pages, views, components, layouts and forms, and fullstack-feature for anything spanning both apps.

Two more keep your project and this template in touch after bootstrapping. boilerplate-sync pulls later template improvements — CI, Dockerfile, tooling, framework code — into your project without touching your product code or renaming your app. boilerplate-backport goes the other way: it takes something generic you built, strips the product-specific parts out of it, and lands it here with the documentation to match.

2b. Customize for Your Project (manual)

After creating your repository, update the following files:

Root package.json

{
  "name": "your-project-name",  // Change this
  "description": "Your project description",
  "author": "Your Name",
  "license": "MIT"  // Or your preferred license
}

apps/server/package.json

{
  "name": "your-server-name",  // Change this
  "description": "Your server description",
  "author": "Your Name",
  "license": "MIT"
}

apps/web/package.json

{
  "name": "your-web-app-name",  // Change this
  "version": "1.0.0"  // Set your initial version
}

apps/web/index.html

Update the title and meta tags:

<title>Your App Name</title>
<meta name="description" content="Your app description">

apps/web/public/manifest.json (PWA)

Update the PWA manifest with your app details:

{
  "name": "Your App Name",
  "short_name": "YourApp",
  "description": "Your app description",
  "theme_color": "#your-color",
  "background_color": "#your-color"
}

Docker Build Arguments

When building Docker images, use your app names:

docker build --build-arg APP_NAME=your-server-name --build-arg VERSION=1.0.0 .

GitHub Actions (Optional)

If you plan to use Docker image publishing workflows, update .github/workflows/*.yml:

  • Update repository references
  • Configure Docker registry credentials
  • Update image naming conventions

Remove or Update Documentation

  • Delete or update AGENTS.md (instructions for AI coding agents)
  • Update this README with your project-specific information
  • Add your own license file if you changed the license

Getting Started

Prerequisites

  • Node.js 24
  • pnpm 10.26.2+ (will be automatically used via packageManager field)
  • PostgreSQL instance
  • Redis instance

Installation

# Clone your new repository
git clone https://github.com/your-username/your-repo.git
cd your-repo

# Install dependencies (pnpm will be automatically installed if needed)
pnpm install

Development

# Build all apps
pnpm build

# Build in watch mode
pnpm build:watch

# Run the backend server (in apps/server/)
cd apps/server
pnpm dev  # Runs on http://localhost:8080 by default
# GraphQL endpoint: http://localhost:8080/graphql
# GraphQL subscriptions: ws://localhost:8080/graphql

# Database operations (in apps/server/)
pnpm db:generate  # Generate migration from schema changes
pnpm db:migrate   # Apply migrations to database

# Run the frontend (in apps/web/)
cd apps/web
pnpm dev  # Runs on http://localhost:5173 by default

# Generate GraphQL types (backend)
cd apps/server
pnpm codegen  # Generates TypeScript types from .graphql files

# Generate GraphQL types (frontend)
cd apps/web
pnpm codegen  # Generates gql.tada types from server schema

# Run linting and formatting
pnpm check

# Auto-fix linting issues
pnpm check:fix

# Run tests (when you add them)
pnpm test
pnpm test:watch

Production Build

# Build all applications for production
pnpm build

# Build Docker images
docker build --build-arg APP_NAME=server --build-arg VERSION=1.0.0 -t your-server:latest .
docker build --build-arg APP_NAME=web --build-arg VERSION=1.0.0 -t your-web:latest .

# Run Docker containers
docker run -p 8080:8080 your-server:latest
docker run -p 80:80 your-web:latest

Project Structure

.
├── apps/
│   ├── server/              # Backend Express application
│   │   ├── src/
│   │   │   ├── config/      # Configuration management
│   │   │   ├── database/    # Database service and schema
│   │   │   ├── error/       # Error types
│   │   │   ├── file-system/ # File system abstraction
│   │   │   ├── http/        # HTTP server and routers
│   │   │   ├── log-streaming/ # Log streaming service
│   │   │   ├── logger/      # Winston logger setup
│   │   │   ├── redis/       # Redis service, queues, and workers
│   │   │   ├── utils/       # Utility functions
│   │   │   ├── applicationContext.ts  # DI container
│   │   │   └── run.ts       # Application entry point
│   │   ├── drizzle/         # Database migrations
│   │   ├── drizzle.config.ts  # Drizzle Kit configuration
│   │   └── config.yaml      # Server configuration
│   │
│   └── web/                 # Frontend React application
│       ├── src/
│       │   ├── components/  # React components
│       │   │   └── ui/      # shadcn/ui components
│       │   ├── pages/       # Page components
│       │   ├── lib/         # Utilities
│       │   └── app.tsx      # App entry point with routing
│       └── public/          # Static assets
│
├── libs/                    # Shared libraries (empty by default)
│
├── .github/
│   └── workflows/           # GitHub Actions CI/CD
│
├── biome.json              # Biome configuration
├── turbo.json              # Turborepo configuration
├── pnpm-workspace.yaml     # pnpm workspace configuration
└── Dockerfile              # Multi-stage Docker build

Available Scripts

Root Level

  • pnpm build - Build all apps in the monorepo
  • pnpm build:watch - Build all apps in watch mode
  • pnpm test - Run tests across all apps
  • pnpm test:watch - Run tests in watch mode
  • pnpm check - Run Biome linting and formatting checks
  • pnpm check:fix - Auto-fix linting issues (includes unsafe fixes)
  • pnpm clean - Remove all build artifacts
  • pnpm update-dependencies - Update all dependencies across the monorepo

Backend (apps/server)

  • pnpm dev - Run server in development mode with hot reload
  • pnpm build - Compile TypeScript to JavaScript
  • pnpm build:watch - Compile in watch mode
  • pnpm db:generate - Generate database migration from schema changes
  • pnpm db:migrate - Apply pending migrations to database

Frontend (apps/web)

  • pnpm dev - Run Vite dev server with HMR
  • pnpm build - Build for production
  • pnpm preview - Preview production build locally
  • pnpm shadcn - Add shadcn/ui components

Technology Stack

Backend

Frontend

Development Tools

Configuration

Backend Configuration

The server supports configuration through YAML files and environment variables. Environment variables take precedence over YAML configuration.

Configuration files (searched in order):

  • config.local.yaml
  • config.yaml
  • config.local.yml
  • config.yml

Environment variables:

The most important variables to configure:

Variable Description Default
DATABASE_CONNECTION_URL PostgreSQL connection string postgres://localhost:5432/server
REDIS_HOST Redis host 127.0.0.1
REDIS_PORT Redis port 6379
REDIS_PASSWORD Redis password —
REDIS_WORKERS Worker configuration (JSON array) —
REDIS_QUEUES Queue configuration (JSON array) —
LOG_LEVEL Logging level (debug, info, warn, error, fatal, notice) info

For the full environment variable reference see docs/configuration.md.

PWA Configuration

The web app includes PWA support. To enable PWA features in development:

PWA_DEV=true pnpm dev

GraphQL Development

Backend GraphQL Setup

The backend uses a modular GraphQL architecture:

File Structure:

apps/server/src/http/routers/
├── graphql/
│   ├── graphQLRouter.ts       # GraphQL server setup
│   ├── graphQLContext.ts      # Context and PubSub types
│   ├── scalars.ts             # Custom scalar definitions
│   ├── common.graphql         # Common scalars
│   └── generated/             # Auto-generated types
└── [feature]/
    ├── graphql/
    │   ├── [feature].graphql  # Schema definition
    │   ├── [feature].query.ts # Query resolvers
    │   ├── [feature].mutation.ts  # Mutation resolvers (optional)
    │   └── [feature].subscription.ts  # Subscription resolvers (optional)
    └── [feature]Module.ts     # Module registration

Adding a New GraphQL Feature:

  1. Create feature directory with schema:
cd apps/server/src/http/routers
mkdir -p myfeature/graphql
  1. Define schema in myfeature/graphql/myfeature.graphql:
type Query {
  myData: MyData!
}

type MyData {
  id: ID!
  name: String!
}
  1. Create resolvers in myfeature/graphql/myfeature.query.ts:
import type { ResolversGQL } from '../../graphql/index.js';

export const myFeatureQuery: Partial<ResolversGQL> = {
  Query: {
    myData: () => ({
      id: '1',
      name: 'Example',
    }),
  },
};
  1. Create module in myfeature/myFeatureModule.ts:
import { loadFiles } from '@graphql-tools/load-files';
import { createModule } from 'graphql-modules';
import { scalars } from '../graphql/index.js';
import { myFeatureQuery } from './graphql/myfeature.query.js';

export const MyFeatureModule = async () => {
  return createModule({
    id: 'myfeature',
    dirname: import.meta.dirname,
    typeDefs: await loadFiles('**/*.graphql', {
      globOptions: { cwd: import.meta.dirname },
    }),
    resolvers: [scalars, myFeatureQuery],
  });
};
  1. Register in HTTPServer.setupRouters() (apps/server/src/http/httpServer.ts):
new GraphQLRouter(
  /* ... */,
  [HealthModule, MyFeatureModule]  // Add your module
)
  1. Generate types:
cd apps/server
pnpm codegen

Frontend GraphQL Setup

The frontend uses Apollo Client with gql.tada for type safety:

Usage Example:

import { useQuery, useSubscription } from '@apollo/client/react';
import { graphql } from '@/lib/graphql';

// Define query with gql.tada
const MyQuery = graphql(`
  query MyData {
    myData {
      id
      name
    }
  }
`);

// Use in component
function MyComponent() {
  const { data } = useQuery(MyQuery);
  return <div>{data?.myData.name}</div>;
}

Subscriptions Example:

const MySubscription = graphql(`
  subscription OnDataChange {
    dataChanged {
      id
      name
    }
  }
`);

function MyComponent() {
  useSubscription(MySubscription, {
    onData: ({ data }) => {
      console.log('Data updated:', data);
    },
  });
}

GraphQL Configuration

Environment Variables:

  • VITE_API_URL - GraphQL HTTP endpoint (default: http://localhost:8080/graphql)
  • VITE_WS_URL - GraphQL WebSocket endpoint (default: ws://localhost:8080/graphql)
  • VITE_GRAPHQL_EXPLORER_ENABLED - Enable the in-app GraphiQL Explorer (default: false)

TypeScript Integration:

  • Backend types generated to apps/server/src/http/routers/graphql/generated/
  • Frontend types generated to apps/web/src/lib/graphql/graphql-env.d.ts
  • Schema exported to apps/server/schema.graphql for client consumption

Adding Shared Libraries

To create shared code between apps:

  1. Create a new package in libs/:
mkdir -p libs/my-shared-lib
cd libs/my-shared-lib
pnpm init
  1. Add it to your workspace and import it in apps:
{
  "dependencies": {
    "@repo/my-shared-lib": "workspace:*"
  }
}

About

Opionated boilerplate to build Fullstack TypeScript web apps

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages