Overview
This document mainly records my thought process behind the technical architecture selection for a full-stack application, along with practical implementation summaries, to serve as a long-term reference for full-stack projects.
There wonβt be tedious code examples here β for details, check the project directly
π Project: nestjs-boilerplate
Project Positioning
Before making any technical choices, itβs important to clarify what this project aims to achieve.
In my daily development, I often take on small projects. Usually, itβs quick to scaffold something with any framework, but it inevitably involves tedious configuration and toolchain integration. Since these projects are small in scope with limited decision time, technical choices and integration workflows are often passive β just βuse whatever worksβ. As a result, thereβs little opportunity for meaningful accumulation, and a lot of time is wasted on redundant setups.
To improve this, I want to prepare a complete, full-stack tech stack in advance. It should allow me to quickly set up projects, while also offering a solid base for diving deeper into vertical project structures and implementation details β instead of repeatedly wasting time on βhorizontal selectionβ each time. This should boost development efficiency and help accumulate reusable experiences and best practices for future projects.
Positioning:
- Full-stack application covering frontend, backend, utility libraries, and UI component libraries
- Suitable for individual developers handling both frontend and backend
- Supports fast MVP prototyping
- Emphasizes maintainability and extensibility
Tech Stack Selection Criteria
Given the vast JavaScript ecosystem and abundant options, I primarily consider the following factors when choosing technologies:
- GitHub Stars Prioritize projects with high star counts and active maintenance. Exclude those with high stars but no recent activity.
- NPM Downloads High download counts β indicates popularity and a lively community where issues are quickly resolved.
- TypeScript Support Must fully support TypeScript to ensure type safety and offer a good developer experience.
- Architecture Adaptability Should flexibly adapt to different project scales and deployment environments.
Monorepo Management Solution
Since the project includes frontend, backend, UI component library, and utility packages, I opted for a Monorepo management solution. This approach enables:
- Centralized management of all modules and unified dependency versions to avoid conflicts.
- Extracting shared modules (like ORM, UI components, TS configs, toolchains) into standalone packages for better modularity and focused business logic.
- Easier local development between packages without needing to publish them.
- Optimized CI/CD pipelines and improved build efficiency.
Finalized Solution:
- Dependency management:
pnpm workspace
- Build & task orchestration:
Turborepo
pnpm
uses its workspace feature to manage dependencies easily across multiple packages in a Monorepo.
Turborepo
is lightweight and flexible, perfectly complementing pnpm
's Monorepo shortcomings. It focuses on configuration management, build processes, supports incremental builds, and caching. Backed by Vercel, itβs actively maintained and reliable.
Other Alternatives:
-
Lerna
: An early Monorepo tool, which became unmaintained around 2020. It was later adopted by the Nx team (Nrwl) in 2022, but is no longer as active β not considered. -
Nx
: A more powerful enterprise-grade Monorepo solution that doesnβt rely onpnpm workspace
for dependency management. It has stricter dependency control and recently introduced AI-first features. Highly promising but comes with a steeper learning curve β not adopting for now.
Backend Tech Choices
Finalized Solution
- Framework:
NestJS
- ORM:
Drizzle ORM
NestJS
can use either Express or Fastify as its underlying HTTP framework. It defaults to Express and can seamlessly integrate third-party Express middleware, making it highly compatible within the ecosystem.
Think of NestJS as a Swiss Army knife built on Express, bundling many useful tools. Of course, one downside is you might not need all those built-in utilities, and you have to work within its dependency injection architecture.
That said, Express alone can get messy, and leveraging NestJS's integrated tools can greatly reduce decision-making and best practice research time. Architecturally, NestJS combines Object-Oriented Programming (OOP), Functional Programming (FP), and Reactive Programming (FRP) concepts β offering strong scalability and a clean project structure.
Drizzle ORM
is lightweight and strikes a good balance between TypeORM and Prisma. Itβs popular for its Serverless compatibility and is one of the most trending ORMs currently.
Other Alternatives
-
Express
: The classic Node.js framework β highly flexible and mature. While building a custom Node.js web framework tailored to your tech stack is tempting, it demands too much time and energy. -
Next.js API Routes
: Great for serverless backends tightly coupled with Next.js frontend, but that's a different development model. For this project, a more traditional backend is preferred for general-purpose use. -
TypeORM
: A veteran ORM framework with high flexibility, but requires custom entity definitions, database access wrappers, transaction control, and migration management. Its configuration can be cumbersome and is better suited for projects needing highly customized SQL logic. -
Prisma
: The most popular TypeScript ORM today β excellent type safety, clean API, and an active community. Best for small to medium projects or cases with stable, rarely changing database schemas. That said, its raw SQL handling experience isnβt ideal.
Frontend Tech Choices
Finalized Solution
- Framework:
React
- Styling:
Tailwind
+ShadCN/UI
This frontend stack follows an AI-first development workflow, tailored for modern AI-assisted coding tools.
Notably, frameworks like V0.dev are built around the React ecosystem β practically making this combination a default stack.
Similarly, Cline also recommends this setup.
For the admin system, a lightweight Vite + React-Router stack is used for fast builds and an excellent development experience β no SSR needed. In cases where SSR is required, Next.js remains the go-to option.
Project Structure Architecture
βββ apps/
β βββ admin/ # Frontend (React 19 + Vite)
β βββ api/ # Backend service based on NestJS
βββ packages/ # Shared packages
β βββ db/ # Drizzle ORM schemas & migration scripts
β βββ ui/ # UI component library based on ShadCN
β βββ lint-config/ # Shared Eslint config
β βββ ts-config/ # Shared TypeScript config
βββ .husky/
βββ pnpm-workspace.yaml # pnpm workspace configuration
βββ turbo.json # Turborepo build config
βββ README.md
Includes a simple admin system β see preview in the header image β or clone nestjs-boilerplate β run to preview.
Top comments (0)