Overview
What AutoMapper TypeScript is, the problems it solves, and when conventions are a good fit.
What AutoMapper does
AutoMapper maps one object shape to another by convention. When source and destination models use matching property names and compatible metadata, the mapper can copy values without per-property configuration.
Use mapping configuration only for the differences: computed values, renamed members, conversions, conditions, or nested types that cannot be inferred.
When it fits
AutoMapper is most useful when:
- destination types are mostly subsets or projections of source types;
- property names follow consistent conventions;
- you repeatedly map domain, persistence, API, or view models;
- central mapping profiles are easier to maintain than scattered constructors and object literals.
If most destination members need custom business logic, explicit transformation code is usually clearer.
How it is structured
Every mapper combines @automapper/core with one mapping strategy:
| Strategy | Use it for |
|---|---|
classes() |
TypeScript classes with @AutoMap() metadata |
pojos() |
Interfaces, types, and plain objects with explicit metadata |
mikro() |
MikroORM entities; extends the classes strategy |
sequelize() |
Sequelize models; extends the classes strategy |
The @automapper/nestjs package integrates a mapper with NestJS dependency injection, profiles, interceptors, and pipes.
The basic flow
import { classes } from "@automapper/classes";
import { createMap, createMapper } from "@automapper/core";
const mapper = createMapper({ strategyInitializer: classes() });
createMap(mapper, User, UserDto);
const dto = mapper.map(user, User, UserDto);
Types follow the destination
The destination identifier drives the result type across single, array, and asynchronous mapping. These types come from the TypeScript compiler; hover an identifier to inspect it in place.
createMap<User, UserDto>(mapper: Mapper, source: ModelIdentifier<User>, destination: ModelIdentifier<UserDto>, ...mappingConfigFns: (MappingConfiguration<User, UserDto> | undefined)[]): Mapping<User, UserDto> (+1 overload)createMap(const mapper: Mappermapper, class UserUser, class UserDtoUserDto);
const const dto: UserDtodto = const mapper: Mappermapper.Mapper.map<User, UserDto>(sourceObject: User, sourceIdentifier: ModelIdentifier<User>, destinationIdentifier: ModelIdentifier<UserDto>, options?: MapOptions<User, UserDto, Record<string, unknown>> | undefined): UserDto (+1 overload)map(const user: Useruser, class UserUser, class UserDtoUserDto);
const const dtos: UserDto[]dtos = const mapper: Mappermapper.Mapper.mapArray<User, UserDto>(sourceArray: User[], sourceIdentifier: ModelIdentifier<User>, destinationIdentifier: ModelIdentifier<UserDto>, options?: MapOptions<User[], UserDto[], Record<string, unknown>> | undefined): UserDto[] (+1 overload)mapArray(const users: User[]users, class UserUser, class UserDtoUserDto);
const const pending: Promise<UserDto>pending = const mapper: Mappermapper.Mapper.mapAsync<User, UserDto>(sourceObject: User, sourceIdentifier: ModelIdentifier<User>, destinationIdentifier: ModelIdentifier<UserDto>, options?: MapOptions<User, UserDto, Record<string, unknown>> | undefined): Promise<UserDto> (+1 overload)Maps `sourceObject` and resolves with the result.mapAsync(const user: Useruser, class UserUser, class UserDtoUserDto);
Continue with Installation, or follow the tutorial for a complete example.