Skip to main content
Version: 7.0 (next)

Decorators Reference

This page provides a complete reference for all decorators available in MikroORM.

Legacy vs ES Decorators

MikroORM v7 supports two types of decorators:

  • Legacy (Experimental) Decorators - Traditional TypeScript decorators requiring experimentalDecorators: true. Import from @mikro-orm/decorators/legacy.
  • ES Spec Decorators - Modern TC39 Stage 3 decorators, supported natively by TypeScript 5.0+. Import from @mikro-orm/decorators/es.
// Legacy decorators
import { Entity, Property } from '@mikro-orm/decorators/legacy';

// ES spec decorators
import { Entity, Property } from '@mikro-orm/decorators/es';

For detailed information about decorator types, metadata providers, and configuration, see Using Decorators.

Entity Definition

Some options affect how the Schema Generator works, and those are SQL only, meaning they affect only SQL drivers - whereas, mongo has no schema.

@Entity()

@Entity decorator is used to mark your model classes as entities. Do not use it for abstract base classes.

ParameterTypeOptionalDescription
tableNamestringyesOverride default collection/table name.
schemastringyesSets the schema name.
collectionstringyesAlias for tableName.
commentstringyesSpecify comment to table. (SQL only)
repository() => EntityRepositoryyesSet custom repository class.
inheritance'tpt'yesFor Table-Per-Type Inheritance.
discriminatorColumnstringyesFor Single Table Inheritance.
discriminatorMapDictionary<string>yesFor Single Table Inheritance.
discriminatorValuenumber | stringyesFor Single Table Inheritance.
forceConstructorbooleanyesEnforce use of constructor when creating managed entity instances
abstractbooleanyesMarks entity as abstract, such entities are inlined during discovery.
readonlybooleanyesDisables change tracking - such entities are ignored during flush.
orderByQueryOrderMap | QueryOrderMap[]yesSet default ordering for this entity. See collections.
@Entity({ tableName: 'authors' })
export class Author { ... }

@Embeddable()

@Embeddable() decorator is used to mark classes as embeddable. Embeddables are classes that are not entities themselves but are embedded in entities.

See Embeddables for more details.

ParameterTypeOptionalDescription
discriminatorColumnstringyesFor polymorphic embeddables.
discriminatorMapDictionary<string>yesFor polymorphic embeddables.
discriminatorValuenumber | stringyesFor polymorphic embeddables.
abstractbooleanyesMarks embeddable as abstract.
@Embeddable()
export class Address {

@Property()
street!: string;

@Property()
city!: string;

}

@Filter()

@Filter() decorator is used to define filters on entities. Filters allow automatic application of conditions to queries.

See Filters for more details.

ParameterTypeOptionalDescription
namestringnoFilter name used to enable/disable it.
condFilterQuery | FunctionnoFilter condition or callback returning the condition.
defaultbooleanyesWhether the filter is enabled by default.
argsbooleanyesWhether the filter accepts arguments.
@Entity()
@Filter({ name: 'isActive', cond: { active: true }, default: true })
export class User {

@PrimaryKey()
id!: number;

@Property()
active!: boolean;

}

Entity Properties

@Property()

@Property() decorator is used to define regular entity property. All following decorators extend the @Property() decorator, so you can also use its parameters there.

ParameterTypeOptionalDescription
fieldNamestringyesOverride default property name (see Naming Strategy).
typestring | Constructor<Type> | TypeyesExplicitly specify the property type. This value is mapped based on the current driver (see Metadata Providers and Custom Types).
runtimeTypestringyesRuntime type of the property. This is the JS type that your property is mapped to, e.g. string or number, and is normally inferred automatically via reflect-metadata. In some cases, the inference won't work, and you might need to specify the runtimeType explicitly - the most common one is when you use a union type with null like foo: number | null.
returningbooleanyesWhether this property should be part of returning clause. Works only in PostgreSQL and SQLite drivers.
onUpdate() => anyyesAutomatically update the property value every time entity gets updated.
persistbooleanyesSet to false to define Shadow Property.
hydratebooleanyesSet to false to disable hydration of this property. Useful for persisted getters.
hiddenbooleanyesSet to true to omit the property when Serializing.
groupsstring[]yesSpecify serialization groups for explicit serialization. If a property does not specify any group, it will be included, otherwise only properties with a matching group are included.
columnTypestringyesSpecify exact database column type for Schema Generator. (SQL only)
lengthnumberyesLength/precision of database column, used for datetime/timestamp/varchar column types for Schema Generator. (SQL only)
defaultanyyesSpecify default column value for Schema Generator. (SQL only)
uniquebooleanyesSet column as unique for Schema Generator. (SQL only)
nullablebooleanyesSet column as nullable for Schema Generator. (SQL only)
unsignedbooleanyesSet column as unsigned for Schema Generator. (SQL only)
commentstringyesSpecify comment of column for Schema Generator. (SQL only)
versionbooleanyesSet to true to enable Optimistic Locking via version field. (SQL only)
concurrencyCheckbooleanyesSet to true to enable Concurrency Check via concurrency fields.
customOrderstring[] | number[] | boolean[]yesSpecify a custom order for the column. (SQL only)

You can use property initializers as usual.

@Property({ length: 50, fieldName: 'first_name' })
name!: string;

@Property({ type: 'date', fieldName: 'born_date' })
born?: string;

@Property({ columnType: 'tinyint' })
age?: number;

@Property({ onUpdate: () => new Date() })
updatedAt = new Date();

@Property()
registered = false;

@PrimaryKey()

@PrimaryKey() decorator is used to define entity's unique primary key identifier.

@PrimaryKey() decorator extend the @Property() decorator, so you can use all its parameters.

Every entity needs to have at least one primary key (see composite primary keys).

Note that if only one PrimaryKey is set, and it's type is number it will be set to auto incremented automatically in all SQL drivers.

@PrimaryKey()
id!: number; // auto increment PK in SQL drivers

@PrimaryKey({ autoincrement: false })
id!: number; // numeric PK without auto increment

@PrimaryKey()
uuid: string = uuid.v4(); // uuid PK in SQL drivers

@PrimaryKey()
_id!: ObjectId; // ObjectId PK in mongodb driver

@SerializedPrimaryKey()

Property marked with @SerializedPrimaryKey() is virtual, it will not be persisted into the database.

For MongoDB, you can define serialized primary key, which will be then used in entity serialization via JSON.stringify() (through method entity.toJSON()). You will be able to use it to manipulate with the primary key as string.

See Usage with MongoDB and Serializing.

@PrimaryKey()
_id: ObjectId;

@SerializedPrimaryKey()
id!: string;

@Enum()

@Enum() decorator extend the @Property() decorator, so you can use all its parameters.

@Enum() decorator can be used for both numeric and string enums. By default, enums are considered numeric, and will be represented in the database schema as tinyint/smallint. For string enums, if you define the enum in same file, its values will be automatically sniffed.

See Defining Entities.

ParameterTypeOptionalDescription
itemsnumber[] | string[] | () => DictionaryyesSpecify enum items explicitly.
@Enum() // with ts-morph metadata provider we do not need to specify anything
enum0 = MyEnum1.VALUE_1;

@Enum(() => MyEnum1) // or @Enum({ items: () => MyEnum1 })
enum1 = MyEnum1.VALUE_1;

@Enum({ type: 'MyEnum2', nullable: true })
enum2?: MyEnum2; // MyEnum2 needs to be defined in current file (can be re-exported)

@Enum({ items: [1, 2, 3] })
enum3 = 3;

@Enum({ items: ['a', 'b', 'c'] })
enum4 = 'a';

@Formula()

@Formula() decorator can be used to map some SQL snippet to your entity. The SQL fragment can be as complex as you want and even include subselects.

See Defining Entities.

ParameterTypeOptionalDescription
formulastring | (columns, table) => string | RawnoSQL fragment that will be part of the select clause. The callback receives columns (unquoted property-to-field mapping) and table (alias info). Use the quote helper for proper identifier quoting.
import { quote } from '@mikro-orm/core';

// Simple string formula (no quoting)
@Formula('obj_length * obj_height * obj_width')
objectVolume?: number;

// Callback with quote helper (recommended for cross-database compatibility)
@Formula(cols => quote`${cols.price} * 1.19`)
priceTaxed?: number;

@Embedded()

@Embedded() decorator is used to embed another class into an entity.

See Embeddables for more details.

ParameterTypeOptionalDescription
entity() => EntityNameyesTarget embeddable class.
prefixstring | booleanyesColumn name prefix. Set to false to disable prefixing.
prefixModeEmbeddedPrefixModeyesHow the prefix is applied.
objectbooleanyesStore as JSON object instead of flattened columns. (SQL only)
arraybooleanyesStore as array of embeddables.
@Entity()
export class User {

@PrimaryKey()
id!: number;

@Embedded(() => Address)
address!: Address;

@Embedded(() => Address, { prefix: 'shipping_' })
shippingAddress!: Address;

@Embedded(() => Address, { object: true })
billingAddress!: Address; // stored as JSON

}

@Index() and @Unique()

Use @Index() to create an index, or @Unique() to create unique constraint. You can use those decorators both on the entity level and on property level. To create compound index, use the decorator on the entity level and provide list of property names via the properties option.

See Defining Entities.

ParameterTypeOptionalDescription
namestringyesindex name
propertiesstring | string[]yeslist of properties, required when using on entity level
typestringyesindex type, not available for @Unique(). Use fulltext to enable support for the $fulltext operator
deferModeimmediate | deferredyesonly for postgres unique constraints
@Entity()
@Index({ properties: ['name', 'age'] }) // compound index, with generated name
@Index({ name: 'custom_idx_name', properties: ['name'] }) // simple index, with custom name
@Unique({ properties: ['name', 'email'] })
export class Author {

@Property()
@Unique()
email!: string;

@Index() // generated name
@Property()
age?: number;

@Index({ name: 'born_index' })
@Property()
born?: string;

}

@Check()

You can define check constraints via @Check() decorator. You can use it either on entity class, or on entity property. It has a required expression property, that can be either a string or a callback that receives columns (property-to-field mapping) and table (table info). The callback can return either a string or a Raw value from the quote helper for proper identifier quoting. Note that you need to use the generic type argument if you want TypeScript suggestions for the property names.

Check constraints are currently supported in PostgreSQL, MySQL 8 and MariaDB drivers. SQLite also supports creating check constraints, but schema inference is currently not implemented. Also note that SQLite does not support adding check constraints to existing tables.

See Defining Entities.

ParameterTypeOptionalDescription
namestringyesconstraint name
propertystringyesproperty name, only used when generating the constraint name
expressionstring | CheckCallbacknoconstraint definition, can be a callback that gets a map of property to column names
@Entity()
// with generated name based on the table name
@Check({ expression: 'price1 >= 0' })
// with explicit name
@Check({ name: 'foo', expression: (columns, table) => `${columns.price1} >= 0` })
export class Book {

@PrimaryKey()
id!: number;

@Property()
price1!: number;

@Property()
@Check({ expression: 'price2 >= 0' })
price2!: number;

@Property({ check: (columns, table) => `${columns.price3} >= 0` })
price3!: number;

}

Entity Relationships

All relationship decorators have entity, cascade and eager optional parameters. If you use the default ReflectMetadataProvider, then entity parameter might be required You will be warned about it being not defined while required during discovery process if you use ReflectMetadataProvider.

You can also use type parameter instead of it - the difference being that type parameter needs to be string, while in entity parameter you can provide a reference (wrapped in a callback to overcome issues with circular dependencies) to the entity, which plays nice with refactoring features in IDEs like WebStorm.

If you explicitly provide entity as a reference, it will enable type checks for other reference parameters like inversedBy or mappedBy.

@ManyToOne()

@ManyToOne() decorator extend the @Property() decorator, so you can use all its parameters.

Many instances of the current Entity refer to One instance of the referred Entity.

See Defining Entities for more examples.

ParameterTypeOptionalDescription
entitystring | () => EntityNameyesSet target entity type.
cascadeCascade[]yesSet what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eagerbooleanyesAlways load the relationship. (Discouraged for use with to-many relations.)
inversedBy(string & keyof T) | (e: T) => anyyesPoint to the inverse side property name.
refbooleanyesWrap the entity in Reference wrapper.
primarybooleanyesUse this relation as primary key.
deleteRulestringyesReferential integrity.
updateRulestringyesReferential integrity.
deferModeimmediate | deferredyesonly for postgres unique constraints
@ManyToOne()
author1?: Author; // type taken via reflection (TsMorphMetadataProvider)

@ManyToOne(() => Author) // explicit type
author2?: Author;

@ManyToOne({ entity: () => Author, cascade: [Cascade.ALL] }) // options object
author3?: Author;

@OneToOne()

@OneToOne() decorator extend the @Property() decorator, so you can use all its parameters.

One instance of the current Entity refers to One instance of the referred Entity.

See Defining Entities for more examples, including bidirectional 1:1.

ParameterTypeOptionalDescription
entitystring | () => EntityNameyesSet target entity type.
cascadeCascade[]yesSet what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eagerbooleanyesAlways load the relationship. (Discouraged for use with to-many relations.)
ownerbooleanyesExplicitly set as owning side (same as providing inversedBy).
inversedBy(string & keyof T) | (e: T) => anyyesPoint to the inverse side property name.
mappedBy(string & keyof T) | (e: T) => anyyesPoint to the owning side property name.
refbooleanyesWrap the entity in Reference wrapper.
orphanRemovalbooleanyesRemove the entity when it gets disconnected from the relationship (see Cascading).
joinColumnstringyesOverride default database column name on the owning side (see Naming Strategy).
primarybooleanyesUse this relation as primary key.
deleteRulestringyesReferential integrity.
updateRulestringyesReferential integrity.
deferModeimmediate | deferredyesonly for postgres unique constraints
// when none of `owner/inverseBy/mappedBy` is provided, it will be considered owning side
@OneToOne()
bestFriend1!: User;

// side with `inversedBy` is the owning one, to define inverse side use `mappedBy`
@OneToOne({ inversedBy: 'bestFriend1', orphanRemoval: true })
bestFriend2!: User;

// when defining it like this, you need to specifically mark the owning side with `owner: true`
@OneToOne(() => User, user => user.bestFriend2, { owner: true, orphanRemoval: true })
bestFriend3!: User;

@OneToMany()

@OneToMany() decorator extend the @Property() decorator, so you can use all its parameters.

One instance of the current Entity has Many instances (references) to the referred Entity.

See Defining Entities for more examples, including bidirectional 1:m.

You need to initialize the value with Collection<T> instance.

ParameterTypeOptionalDescription
mappedBy(string & keyof T) | (e: T) => anynoPoint to the owning side property name.
entitystring | () => EntityNameyesSet target entity type.
cascadeCascade[]yesSet what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eagerbooleanyesAlways load the relationship. (Discouraged for use with to-many relations.)
orphanRemovalbooleanyesRemove the entity when it gets disconnected from the connection (see Cascading).
orderBy{ [field: string]: QueryOrder }yesSet default ordering condition.
joinColumnstringyesOverride default database column name on the owning side (see Naming Strategy).
inverseJoinColumnstringyesOverride default database column name on the inverse side (see Naming Strategy).
@OneToMany(() => Book, book => book.author)
books1 = new Collection<Book>(this);

@OneToMany({ mappedBy: 'author', cascade: [Cascade.ALL] })
books2 = new Collection<Book>(this); // target entity type can be read via `TsMorphMetadataProvider` too

@ManyToMany()

@ManyToMany() decorator extend the @Property() decorator, so you can use all its parameters.

Many instances of the current Entity refers to Many instances of the referred Entity.

See Defining Entities for more examples, including bidirectional m:n.

You need to initialize the value with Collection<T> instance.

ParameterTypeOptionalDescription
entitystring | () => EntityNameyesSet target entity type.
cascadeCascade[]yesSet what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see Cascading).
eagerbooleanyesAlways load the relationship. (Discouraged for use with to-many relations.)
ownerbooleanyesExplicitly set as owning side (same as providing inversedBy).
inversedBy(string & keyof T) | (e: T) => anyyesPoint to the inverse side property name.
mappedBy(string & keyof T) | (e: T) => anyyesPoint to the owning side property name.
orderBy{ [field: string]: QueryOrder }yesSet default ordering condition.
fixedOrderbooleanyesForce stable insertion order of items in the collection (see Collections).
fixedOrderColumnstringyesOverride default order column name (id).
pivotTablestringyesOverride default name for pivot table (see Naming Strategy).
joinColumnstringyesOverride default database column name on the owning side (see Naming Strategy).
inverseJoinColumnstringyesOverride default database column name on the inverse side (see Naming Strategy).
@ManyToMany({ entity: () => BookTag, cascade: [], fixedOrderColumn: 'order' })
tags = new Collection<BookTag>(this); // m:n with autoincrement PK

@ManyToMany(() => BookTag, undefined, { pivotTable: 'book_to_tag_unordered', orderBy: { name: QueryOrder.ASC } })
tagsUnordered = new Collection<BookTag>(this); // m:n with composite PK

Lifecycle Hooks

You can use lifecycle hooks to run some code when entity gets persisted. You can mark any of entity methods with them, you can also mark multiple methods with same hook.

All hooks support async methods with one exception - @OnInit.

@OnInit()

Fired when new instance of entity is created, either manually em.create(), or automatically when new entities are loaded from database

@OnInit is not fired when you create the entity manually via its constructor (new MyEntity())

@OnInit()
doStuffOnInit(args: EventArgs<this>) {
this.fullName = `${this.firstName} - ${this.lastName}`; // initialize shadow property
}

@OnLoad()

Fired when new entities are loaded from database. Unlike @OnInit(), this will be fired only for fully loaded entities (not references). The method can be async.

@OnLoad()
async doStuffOnLoad(args: EventArgs<this>) {
// ...
}

@BeforeCreate()

Fired right before the new entity is persisted into the database.

@BeforeCreate()
async doStuffBeforeCreate(args: EventArgs<this>) {
// ...
}

@AfterCreate()

Fired right after the new entity is created in the database and merged to identity map. Since this event entity will have reference to EntityManager and will be enabled to call wrap(entity).init() method (including all entity references and collections).

@AfterCreate()
async doStuffAfterCreate(args: EventArgs<this>) {
// ...
}

@BeforeUpdate()

Fired right before the entity is updated in the database.

@BeforeUpdate()
async doStuffBeforeUpdate(args: EventArgs<this>) {
// ...
}

@AfterUpdate()

Fired right after the entity is updated in the database.

@AfterUpdate()
async doStuffAfterUpdate(args: EventArgs<this>) {
// ...
}

@BeforeUpsert()

Fired right before the entity is upserted into the database.

@BeforeUpsert()
async doStuffBeforeUpsert(args: EventArgs<this>) {
// ...
}

@AfterUpsert()

Fired right after the entity is upserted into the database.

@AfterUpsert()
async doStuffAfterUpsert(args: EventArgs<this>) {
// ...
}

@BeforeDelete()

Fired right before the record is deleted from database. It is fired only when removing entity or entity reference, not when deleting records by query.

@BeforeDelete()
async doStuffBeforeDelete(args: EventArgs<this>) {
// ...
}

@AfterDelete()

Fired right after the record gets deleted from database, and it is unset from the identity map.

@AfterDelete()
async doStuffAfterDelete(args: EventArgs<this>) {
// ...
}

Method Decorators

@CreateRequestContext()

@CreateRequestContext() decorator can be used to create a new RequestContext for an async method. This is useful for ensuring each request has its own isolated EntityManager fork.

See Identity Map for more details about request context.

ParameterTypeOptionalDescription
contextProvider() => MikroORM | () => EntityManageryesCallback to get the ORM instance or EntityManager.
export class MyService {

constructor(private readonly orm: MikroORM) {}

@CreateRequestContext()
async doSomething() {
// this method now runs in its own request context
const em = this.orm.em; // this is a forked EntityManager
}

}

// or with explicit context provider
export class MyService {

constructor(private readonly em: EntityManager) {}

@CreateRequestContext((self: MyService) => self.em)
async doSomething() {
// ...
}

}

@EnsureRequestContext()

@EnsureRequestContext() works like @CreateRequestContext() but reuses an existing context if one is already available.

@EnsureRequestContext()
async doSomething() {
// reuses existing context or creates a new one
}

@Transactional()

@Transactional() decorator wraps the method in a transaction. It supports all options from em.transactional().

See Transactions for more details.

ParameterTypeOptionalDescription
context() => MikroORM | () => EntityManageryesCallback to get the ORM instance or EntityManager.
contextNamestringyesName of the context to use.
isolationLevelIsolationLevelyesTransaction isolation level.
readOnlybooleanyesWhether the transaction is read-only.
propagationTransactionPropagationyesTransaction propagation mode. Defaults to REQUIRED.
export class MyService {

constructor(private readonly orm: MikroORM) {}

@Transactional()
async createUser(data: CreateUserDto) {
// this method runs in a transaction
const user = this.orm.em.create(User, data);
await this.orm.em.persist(user).flush();
return user;
}

@Transactional({ isolationLevel: IsolationLevel.SERIALIZABLE })
async transferMoney(from: number, to: number, amount: number) {
// runs with SERIALIZABLE isolation level
}

}

Unlike em.transactional(), the @Transactional() decorator uses REQUIRED propagation by default, which means it will join an existing transaction if one is active.