| name | nestjs-import-enforcer |
| description | Automatically enforce absolute imports from barrel exports in NestJS. Use when writing imports, creating TypeScript files, or organizing NestJS module structure. |
Import Convention Enforcer (NestJS)
Auto-enforces absolute imports from barrel exports for clean, maintainable NestJS code.
When This Skill Activates
I automatically run when:
- User writes or modifies TypeScript files
- User creates entities, DTOs, services, controllers
- User imports from other modules
- User mentions "import", "NestJS", "module"
- User organizes project structure
Required Import Pattern (MANDATORY)
✅ CORRECT - Absolute imports from barrel exports:
import { User, Profile } from 'src/users/entities'
import { UsersService } from 'src/users/services'
import { CreateUserDto, UpdateUserDto } from 'src/users/dto'
import { JwtAuthGuard } from 'src/auth/guards'
import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
❌ WRONG - Relative imports:
import { User } from './entities/user.entity'
import { UsersService } from '../services/users.service'
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'
❌ WRONG - Import from specific files (not barrel):
import { User } from 'src/users/entities/user.entity'
Auto-Fix Process
Step 1: Detect Violations
import { User } from './entities/user.entity'
import { CreateUserDto } from '../dto/create-user.dto'
import { AuthService } from '../../auth/services/auth.service'
Step 2: Convert to Absolute Barrel Imports
import { User } from 'src/users/entities'
import { CreateUserDto } from 'src/users/dto'
import { AuthService } from 'src/auth/services'
Step 3: Organize Import Order
import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User, Profile } from 'src/users/entities'
import { CreateUserDto, UpdateUserDto } from 'src/users/dto'
import { AuthService } from 'src/auth/services'
Import Organization Rules
1. Import Categories (Top to Bottom)
import { Module, Injectable, Controller } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { ApiTags, ApiOperation } from '@nestjs/swagger'
import { User } from 'src/users/entities'
import { UsersService } from 'src/users/services'
import { JwtAuthGuard } from 'src/auth/guards'
import { CreateUserDto } from './dto'
import { UserResponseDto } from './dto'
2. Named Imports (Alphabetical)
import { Injectable, Logger, NotFoundException } from '@nestjs/common'
import { NotFoundException, Injectable, Logger } from '@nestjs/common'
Module Structure with Barrel Exports
users/
├── users.module.ts
├── entities/
│ ├── user.entity.ts
│ └── index.ts # export * from './user.entity'
├── dto/
│ ├── create-user.dto.ts
│ └── index.ts # export * from './create-user.dto'
├── services/
│ ├── users.service.ts
│ └── index.ts # export * from './users.service'
└── controllers/
├── users.controller.ts
└── index.ts # export * from './users.controller'
Complete Service Example
import { Injectable, NotFoundException } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from 'src/users/entities'
import { CreateUserDto, UpdateUserDto } from 'src/users/dto'
import { AuthService } from 'src/auth/services'
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly authService: AuthService,
) {}
async create(dto: CreateUserDto): Promise<User> {
const user = this.userRepository.create(dto)
return this.userRepository.save(user)
}
async findOne(id: string): Promise<User> {
const user = await this.userRepository.findOne({ where: { id } })
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`)
}
return user
}
}
Complete Controller Example
import {
Controller,
Get,
Post,
Body,
Param,
UseGuards,
} from '@nestjs/common'
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'
import { UsersService } from 'src/users/services'
import { CreateUserDto, UpdateUserDto, UserResponseDto } from 'src/users/dto'
import { JwtAuthGuard } from 'src/auth/guards'
import { CurrentUser } from 'src/common/decorators'
import { User } from 'src/users/entities'
@ApiTags('users')
@Controller('users')
@UseGuards(JwtAuthGuard)
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@ApiOperation({ summary: 'Create new user' })
async create(@Body() dto: CreateUserDto): Promise<UserResponseDto> {
return this.usersService.create(dto)
}
@Get(':id')
@ApiBearerAuth()
@ApiOperation({ summary: 'Get user by ID' })
async findOne(@Param('id') id: string): Promise<UserResponseDto> {
return this.usersService.findOne(id)
}
}
Cross-Module Imports
import { Injectable } from '@nestjs/common'
import { User } from 'src/users/entities'
import { UsersService } from 'src/users/services'
import { Product } from 'src/products/entities'
import { ProductsService } from 'src/products/services'
@Injectable()
export class OrdersService {
constructor(
private readonly usersService: UsersService,
private readonly productsService: ProductsService,
) {}
async createOrder(userId: string, productId: string) {
const user = await this.usersService.findOne(userId)
const product = await this.productsService.findOne(productId)
}
}
Local Module Imports
Within the same module, you can use local barrel imports:
import { Injectable } from '@nestjs/common'
import { User } from '../entities'
import { CreateUserDto } from '../dto'
import { User } from 'src/users/entities'
import { CreateUserDto } from 'src/users/dto'
TypeScript Configuration
Ensure tsconfig.json supports absolute imports:
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"src/*": ["src/*"]
}
}
}
Common Violations
Violation 1: Relative Imports
import { User } from './entities/user.entity'
import { UsersService } from '../services/users.service'
import { User } from 'src/users/entities'
import { UsersService } from 'src/users/services'
Violation 2: Importing from Specific Files
import { User } from 'src/users/entities/user.entity'
import { User } from 'src/users/entities'
Violation 3: Inconsistent Paths
import { User } from 'src/users/entities'
import { CreateUserDto } from './dto/create-user.dto'
import { User } from 'src/users/entities'
import { CreateUserDto } from 'src/users/dto'
Module Pattern Best Practices
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { User, Profile } from './entities'
import { UsersService } from './services'
import { UsersController } from './controllers'
import { AuthModule } from 'src/auth/auth.module'
@Module({
imports: [
TypeOrmModule.forFeature([User, Profile]),
AuthModule,
],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
Success Criteria
✅ ALL imports use absolute paths from src/
✅ ALL imports use barrel exports
✅ NO relative imports
✅ Imports organized by category
✅ Consistent import style across project
Skill Behavior
I am PROACTIVE:
- I detect relative imports AUTOMATICALLY
- I convert to absolute barrel imports IMMEDIATELY
- I organize import order
- I ensure barrel exports exist
- I explain import patterns
I do NOT:
- Allow relative imports
- Allow imports from specific files (skip barrels)
- Accept inconsistent import styles
I ALWAYS:
- Use
src/ absolute paths
- Import from barrel exports (
index.ts)
- Organize imports by category
- Keep imports clean and maintainable
This ensures clean, maintainable NestJS import structure from day one.