阅读视图

发现新文章,点击刷新页面。

2026 年,值得前端全栈尝试的 NestJS 技术栈组合 😍😍😍

我正在开发 DocFlow,它是一个完整的 AI 全栈协同文档平台。该项目融合了多个技术栈,包括基于 Tiptap 的富文本编辑器、NestJs 后端服务、AI 集成功能和实时协作。在开发过程中,我积累了丰富的实战经验,涵盖了 Tiptap 的深度定制、性能优化和协作功能的实现等核心难点。

如果你对 AI 全栈开发、Tiptap 富文本编辑器定制或 DocFlow 项目的完整技术方案感兴趣,欢迎加我微信 yunmz777 进行私聊咨询,获取详细的技术分享和最佳实践。

对很多想从前端转向全栈的同学来说,NestJS 是一个非常友好的选择:语法风格接近前端熟悉的 TypeScript,又借鉴了后端常见的模块化与依赖注入模式,可以在保留前端开发舒适度的同时,比较轻松地搭起一套“像样的后端服务”。

如果目标不仅是写几个简单接口,而是要扛起鉴权、实时协同、AI 能力,还要自己搭建和维护数据库、缓存、搜索、对象存储、监控这些基础设施,那么就需要一套偏“自托管、自运维”的 NestJS 技术栈组合。

这里推荐的技术栈选择标准主要有三点:

  1. NestJS 生态高度契合,有成熟的官方或社区集成;
  2. 能够支撑中大型文档、知识类应用的性能和复杂度,比如协同编辑、全文检索、RAG、任务队列等;
  3. 个人或小团队也能在合理成本内自行部署和维护,比如使用 Prisma + MySqlRedisElasticsearchMinIO 这类开源组件。

接下来就按照从框架、运行时到数据层、搜索、队列、AI 的顺序,分享一套适合前端转全栈使用的 NestJS 核心技术栈,代码也尽量贴近实战,方便直接改造复用。

NestJSTypeScript

NestJS 是整个后端的“框架壳子”,负责模块划分、依赖注入、装饰器等基础能力;TypeScript 则是地基,把很多原本要靠经验避免的错误提前到编译期发现,例如 Controller 入参、Service 返回值、配置对象等。

实际项目中,一般会开启严格模式,再结合全局的 ValidationPipeclass-transformer,把请求里的原始 JSON 自动转换成带类型的 DTO 实例,从而减少 any 的使用、避免脏数据流入业务层。

基本使用案例:

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      transform: true,
    }),
  );
  await app.listen(3000);
}

bootstrap();

Fastify@nestjs/platform-fastify

Fastify 是一个高性能 HTTP 引擎,相比 Express 更轻量、更适合高并发场景;@nestjs/platform-fastify 负责把 Fastify 接进 Nest,让你在业务层依然只写标准的 Controller、Guard、Interceptor 等。

搭配 @fastify/helmet@fastify/rate-limit@fastify/cookie@fastify/secure-session@fastify/multipart@fastify/static,可以在统一框架里完成安全头、限流、会话、上传和静态资源托管。

基本使用案例:

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  await app.listen(3000, '0.0.0.0');
}

bootstrap();

@nestjs/config

@nestjs/config 是 Nest 官方的配置模块,用来统一管理多环境配置。思路很简单:所有数据库地址、第三方秘钥、开关配置等,都通过 ConfigService 读取,而不是在代码里到处散落 process.env

推荐的做法是为不同领域写独立的配置工厂,然后在对应模块中注入使用。

基本使用案例:

// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: '.env',
    }),
  ],
})
export class AppModule {}
// some.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class SomeService {
  constructor(private readonly configService: ConfigService) {}

  getDbUrl() {
    return this.configService.get<string>('DATABASE_URL');
  }
}

PassportJWT

@nestjs/passport@nestjs/jwt 提供了一整套认证基础设施:Passport 统一管理各种认证策略(本地、JWT、OAuth 等),JWT 提供无状态令牌,让前后端分离、多端访问更容易管理。

常见流程是:通过本地策略验证用户名密码,登录成功后签发 JWT,后续请求通过 AuthGuard('jwt') 验证;接入第三方登录(如 GitHub)时,仅需增加新的 Passport 策略。

基本使用案例:

// auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.register({
      secret: 'secret', // 实际项目请从 ConfigService 读取
    }),
  ],
  providers: [JwtStrategy],
  exports: [PassportModule, JwtModule],
})
export class AuthModule {}
// some.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller('profile')
export class ProfileController {
  @UseGuards(AuthGuard('jwt'))
  @Get()
  getProfile() {
    return { ok: true };
  }
}

WebSocketSocket.IO

当系统需要即时通知、在线状态、协同编辑时,可以使用 @nestjs/websockets 搭配 @nestjs/platform-socket.iosocket.ioGateway 充当“长连接入口”,负责管理连接、房间和事件。

更高级的协同场景中,还可以引入 hocuspocusyjsy-prosemirror 来负责文档协同算法,Nest 只需要负责连接管理和权限校验。

基本使用案例:

// chat.gateway.ts
import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  MessageBody,
} from '@nestjs/websockets';
import { Server } from 'socket.io';

@WebSocketGateway()
export class ChatGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('message')
  handleMessage(@MessageBody() data: string) {
    this.server.emit('message', data);
  }
}

Prisma

Prisma 通过独立的 schema.prisma 文件定义模型,并生成强类型的 PrismaClient,非常适合在 Nest 的 Service 层中使用。它把数据库迁移、数据建模、类型安全绑在一起,能明显降低 SQL 错误和字段拼写错误的概率。

在 Service 中,直接注入封装好的 PrismaService,就可以用类型安全的方式进行增删改查。

基本使用案例:

// user.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '@/common/prisma/prisma.service';

@Injectable()
export class UserService {
  constructor(private readonly prisma: PrismaService) {}

  findAll() {
    return this.prisma.user.findMany();
  }
}

Redisioredis

Redis 是常见的缓存与中间层,而 ioredis 是稳定好用的 Node 客户端组合。它通常用于三个方向:缓存(加速读取)、分布式协调(锁、限流、防重复)、短期数据存储(会话、任务状态等)。

在 Nest 中一般会封装一个 RedisService,对外暴露 getsetincr 等方法,避免直接在业务里使用底层客户端。

基本使用案例:

// redis.service.ts
import { Injectable, OnModuleInit } from '@nestjs/common';
import { Redis } from 'ioredis';

@Injectable()
export class RedisService implements OnModuleInit {
  private client: Redis;

  onModuleInit() {
    this.client = new Redis('redis://localhost:6379');
  }

  async get(key: string) {
    return this.client.get(key);
  }

  async set(key: string, value: string, ttlSeconds?: number) {
    if (ttlSeconds) {
      await this.client.set(key, value, 'EX', ttlSeconds);
    } else {
      await this.client.set(key, value);
    }
  }
}

BullMQ

BullMQ 是基于 Redis 的任务队列,@nestjs/bullmq 让你可以用装饰器方式定义队列和消费者。它适合承载各种耗时任务,例如大文件解析、批量导入导出、调用外部 AI 接口等。

这样可以把重任务从 HTTP 请求中剥离,避免接口超时,用户只需拿到一个“任务已受理”的 ID。

基本使用案例:

消费者(处理任务):

// task.processor.ts
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';

@Processor('tasks')
export class TaskProcessor extends WorkerHost {
  async process(job: Job) {
    // 这里处理耗时任务
    console.log('processing job', job.id, job.data);
  }
}

生产者(投递任务):

// task.service.ts
import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';

@Injectable()
export class TaskService {
  constructor(@InjectQueue('tasks') private readonly queue: Queue) {}

  async createTask(payload: any) {
    const job = await this.queue.add('process', payload);
    return { jobId: job.id };
  }
}

Elasticsearch

Elasticsearch 在文档和知识类系统中通常用作结构化搜索与日志索引引擎。通过 @elastic/elasticsearch 客户端可以在 Nest 的 Service 里封装搜索接口,对外统一暴露“搜索文档”“搜索日志”等能力。

相对数据库原生查询,Elasticsearch 更擅长复杂查询、聚合统计、模糊搜索与搜索结果排序,是提升搜索体验的关键组件。

基本使用案例:

封装搜索 Service:

// search.service.ts
import { Injectable } from '@nestjs/common';
import { Client } from '@elastic/elasticsearch';

@Injectable()
export class SearchService {
  private client = new Client({ node: 'http://localhost:9200' });

  async searchDocs(keyword: string) {
    const res = await this.client.search({
      index: 'documents',
      query: {
        multi_match: {
          query: keyword,
          fields: ['title', 'content'],
        },
      },
    });
    return res.hits.hits;
  }
}

对象存储(MinIO

当系统有大量文件(如 PDFWord、图片、音频)时,本地磁盘很快就会吃不消,这时可以用自建的 MinIO 集群来做对象存储。它负责长期保存大文件,后端只需要关心对象名和访问地址,不必再直接管理磁盘。

在 Nest 中通常会封装一个存储 Service,对上层暴露“上传文件”“生成下载地址”等方法;同时配合 imagekitsharpexiftool-vendoredpdf-parsemammoth 等,对文件做压缩、预览、元信息与文本提取等处理。

基本使用案例:

// storage.service.ts
import { Injectable } from '@nestjs/common';
import { Client } from 'minio';

@Injectable()
export class StorageService {
  private client = new Client({
    endPoint: 'localhost',
    port: 9000,
    useSSL: false,
    accessKey: 'minio',
    secretKey: 'minio123',
  });

  async upload(bucket: string, objectName: string, buffer: Buffer) {
    await this.client.putObject(bucket, objectName, buffer);
    return { bucket, objectName };
  }
}

@nestjs/swagger

@nestjs/swagger 负责从 Controller 和 DTO 的装饰器中生成 OpenAPI 文档,让接口定义和代码实现保持同步,不再需要单独维护一份容易过期的接口文档。

在前后端分离项目中,Swagger 文档可以同时服务前端、测试与产品:前端对齐请求和响应结构,测试做接口验证,产品了解后端已有能力。

基本使用案例:

// main.ts 片段
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const config = new DocumentBuilder()
    .setTitle('API 文档')
    .setDescription('服务接口说明')
    .setVersion('1.0')
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('docs', app, document);

  await app.listen(3000);
}

class-validatorclass-transformer

class-validator 通过在 DTO 类属性上添加装饰器(如 IsStringIsIntIsOptional 等)定义字段的合法规则,class-transformer 负责把原始请求 JSON 转换成 DTO 实例。配合全局 ValidationPipe,可以保证进入 Controller 的数据已经过校验和转换。

这一体系大大减少了手写 if 校验的重复劳动,同时确保错误请求在统一入口被拦截并抛出合适的 HTTP 异常。

基本使用案例:

// create-user.dto.ts
import { IsEmail, IsString, MinLength } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(6)
  password: string;
}
// user.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';

@Controller('users')
export class UserController {
  @Post()
  create(@Body() dto: CreateUserDto) {
    return dto;
  }
}

PrometheusTerminus

@willsoto/nestjs-prometheus 搭配 prom-client 可以方便地暴露各种指标端点,例如 HTTP 延迟、错误率、队列堆积情况等;@nestjs/terminus 则专注于健康检查,通过多种 HealthIndicator 检查数据库、RedisElasticsearchQdrant 等依赖服务是否可用。

在生产环境下,这两者为“可观测性”打基础,使运维和开发可以快速感知和定位问题。

基本使用案例:

// health.controller.ts
import { Controller, Get } from '@nestjs/common';
import {
  HealthCheck,
  HealthCheckService,
  TypeOrmHealthIndicator,
} from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private db: TypeOrmHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () => this.db.pingCheck('database'),
    ]);
  }
}

OpenAILangChain

openai 提供与大模型交互的基础接口,而 langchain@langchain/core@langchain/community@langchain/openai@langchain/textsplitters 则把模型调用、提示模板、工具调用、长文档切片等复杂逻辑抽象成可组合的模块。对于文档工作流类项目,这一层就是从“普通文档系统”升级为“智能文档系统”的关键。

在 Nest 中,通常会拆出一个 AI 模块,把“向量检索 + RAG + 模型调用”封装在 Service 里,再通过少量 HTTP 接口暴露出问答、总结、润色等能力。

基本使用案例:

// ai.service.ts
import { Injectable } from '@nestjs/common';
import OpenAI from 'openai';

@Injectable()
export class AiService {
  private client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

  async chat(prompt: string) {
    const res = await this.client.chat.completions.create({
      model: 'gpt-4.1-mini',
      messages: [{ role: 'user', content: prompt }],
    });
    return res.choices[0]?.message?.content ?? '';
  }
}

总结

如果只是想把接口“跑起来”,也许只要 NestJS 加上一两个库就够用;但一旦要扛起鉴权、实时协同、AI、文件与搜索这些完整能力,就很容易演变成这篇文章前面列出来的这一整套技术栈:NestJS + TypeScript 打基础,Fastify 提供高性能 HTTP 入口,Prisma + MySql 管数据,Redis + BullMQ 管缓存和队列,Elasticsearch 管搜索,MinIO 管文件,再加上 @nestjs/swaggerclass-validatorPrometheusTerminusOpenAILangChain 这些周边,让项目从“能跑”变成“好用、可维护、可扩展”。

对前端转全栈来说,这套组合有两个现实的好处:一是语法和思路都围绕 TypeScript 展开,上手成本可控;二是每一个环节都有成熟的 Nest 集成(模块、装饰器、示例代码),可以按需逐步引入,而不必一口气吃下全部。你可以先用 NestJS + Prisma + Redis 起一个简单项目,再慢慢把队列、搜索、对象存储和 AI 能力补上,最终搭出一套适合自己长期维护的后端脚手架。

❌