Добавить в корзинуПозвонить
Найти в Дзене
RMTe4m

🛠 Почему я выбрал NestJS для своих проектов и больше не хочу обратно на Express

Когда я только начинал писать back, Express казался всем, чем должен быть фреймворк: лёгкий, гибкий, без лишнего. Пишешь app.get(...), app.post(...) — и поехали. Всё просто. Казалось бы, зачем менять? Но чем больше проектов, тем больше я начал замечать: простота Express оборачивается беспорядком. Код начинал обрастать utils.js, services.js, бесконечными if и копипастой. Один маршрут тянул другой, бизнес-логика расползалась по проекту, и через пару недель самому страшно было открывать контроллер. NestJS мне показал коллега. Я открыл документацию, увидел @Injectable(), @Controller(), @Module() — и, честно, сразу закрыл. Показалось слишком «церемониально», особенно после Express. Но интерес остался. Через неделю решил попробовать собрать pet-проект на Nest — и втянулся. Первое, что подкупает в Nest — архитектура идёт сразу. Тебе не нужно придумывать структуру, не надо решать «а где мне писать бизнес-логику, а где руты». Модули позволяют изолировать фичи. DI-контейнер работает прозрачно,
Оглавление

Когда я только начинал писать back, Express казался всем, чем должен быть фреймворк: лёгкий, гибкий, без лишнего. Пишешь app.get(...), app.post(...) — и поехали. Всё просто. Казалось бы, зачем менять?

Но чем больше проектов, тем больше я начал замечать: простота Express оборачивается беспорядком.

Код начинал обрастать utils.js, services.js, бесконечными if и копипастой. Один маршрут тянул другой, бизнес-логика расползалась по проекту, и через пару недель самому страшно было открывать контроллер.

📦 Впервые увидел NestJS — и закрыл вкладку

NestJS мне показал коллега. Я открыл документацию, увидел @Injectable(), @Controller(), @Module() — и, честно, сразу закрыл. Показалось слишком «церемониально», особенно после Express.

Но интерес остался. Через неделю решил попробовать собрать pet-проект на Nest — и втянулся.

📐 Система из коробки

Первое, что подкупает в Nest — архитектура идёт сразу. Тебе не нужно придумывать структуру, не надо решать «а где мне писать бизнес-логику, а где руты».

Модули позволяют изолировать фичи. DI-контейнер работает прозрачно, зависимости мокаются удобно.

Вот, например, типичный AuthModule:

// auth.module.ts
@Module({
controllers: [AuthController],
providers: [AuthService],
imports: [JwtModule.register({ secret: 'super-secret' }), UsersModule],
})
export class AuthModule {}

Или Guard для проверки прав доступа:

// roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return request.user?.role === 'admin';
}
}

📌 Уже с этим Nest показывает: он не про «быстро наклепать». Он про «написал один раз — поддерживаешь годами».

✅ Что действительно решает

Вот что меня окончательно убедило, что Nest — мой основной выбор:

  • 🧱 Модули: проект делится по фичам. У меня сейчас 12 модулей, и всё стабильно.
  • 🧪 Тесты: благодаря DI легко замокать зависимости и писать unit-тесты без боли.

// auth.service.spec.ts
describe('AuthService', () => {
let service: AuthService;

beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
AuthService,
{
provide: UsersService,
useValue: { findOne: jest.fn() },
},
],
}).compile();

service = module.get<AuthService>(AuthService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});

  • 🔐 Guards и Pipes: наконец-то не нужно проверять роль и типы руками.
  • 🔄 Интеграция с WebSocket: всё через @WebSocketGateway() — удобно и понятно.
  • 📄 Swagger: подключается одной строчкой и помогает документировать API.

// main.ts
const config = new DocumentBuilder()
.setTitle('My API')
.setDescription('Описание API')
.setVersion('1.0')
.addBearerAuth()
.build();

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

🪤 Где споткнулся

Чтобы не казаться розовыми очками, делюсь фейлами:

  • 🚫 Попался в циклические импорты (Module A импортирует B, а B — A). Решается через forwardRef(), но не сразу очевидно.
  • 🤯 Пытался загрузить данные в constructor сервиса — Nest не простил. Надо использовать onModuleInit().

@Injectable()
export class ExampleService implements OnModuleInit {
async onModuleInit() {
await this.loadInitialData();
}
}

  • 📦 Слишком увлёкся модульностью — создавал модуль на каждый чих. Потом пришлось объединять, чтобы не плодить сущности без смысла.

🧠 Что ценят опытные разработчики

Если ты хочешь делать масштабируемые приложения, Nest даёт:

  • Чёткую реализацию SOLID-принципов
  • Возможность вынести любой модуль в отдельный сервис (вплоть до микросервисов)
  • Чистую архитектуру с минимумом боли

💬 Вывод

Express — классная штука. Но Nest — это про системную разработку.

Когда у тебя 3–5 модулей и всё растёт, Nest начинает реально экономить твои нервы.

Сейчас я пишу проекты только на Nest. Потому что он даёт мне структуру, которую я раньше собирал вручную. А теперь я просто пишу код, а не борюсь с хаосом.

🔜 Что дальше?

В следующей статье расскажу:

  • Как я связываю Nest и Next в одном проекте
  • Как строю архитектуру с разделением front и back
  • Как всё это живёт в Docker и деплоится в 1 команду

Подписывайся, если интересно. А если хочешь поддержать — черкани комментарий или просто пришли статью другу 😄