# Source: https://mikro-orm.io/docs/upgrading-v3-to-v4.md

# Upgrading from v3 to v4

> Following sections describe (hopefully) all breaking changes, most of them might be not valid for you, like if you do not use custom `NamingStrategy` implementation, you do not care about the interface being changed.

## Node 10.13.0+ required[​](#node-10130-required "Direct link to Node 10.13.0+ required")

Support for older node versions was dropped.

## TypeScript 3.7+ required[​](#typescript-37-required "Direct link to TypeScript 3.7+ required")

Support for older TypeScript versions was dropped.

## Monorepo[​](#monorepo "Direct link to Monorepo")

The ORM has been split into several packages. In v4 one needs to require `@mikro-orm/core` and a driver package, e.g. `@mikro-orm/mysql`. This driver package already contains the `mysql2` dependency, so you can remove that from your `package.json`.

* `@mikro-orm/core`
* `@mikro-orm/reflection` - `TsMorphMetadataProvider`
* `@mikro-orm/cli` - CLI support, requires entity-generator, migrator and knex
* `@mikro-orm/knex` - SQL support
* `@mikro-orm/entity-generator`
* `@mikro-orm/migrations`
* `@mikro-orm/mysql`
* `@mikro-orm/mariadb`
* `@mikro-orm/mysql-base` - Common implementation for mysql and mariadb (internal)
* `@mikro-orm/sqlite`
* `@mikro-orm/postgresql`
* `@mikro-orm/mongodb`

> For easier transition, meta package mikro-orm is still present, reexporting core, reflection, migrations, entity-generator and cli packages. You should **not** install both `mikro-orm` and `@mikro-orm/core` packages together.

> You should prefer the `@mikro-orm/core` over `mikro-orm` package, there were weird dependency issues reported with the `mikro-orm` meta-package.

## Default metadata provider is now `ReflectMetadataProvider`[​](#default-metadata-provider-is-now-reflectmetadataprovider "Direct link to default-metadata-provider-is-now-reflectmetadataprovider")

If you want to use ts-morph, you need to install `@mikro-orm/reflection` package and enable the provider explicitly in the ORM config, as described [here](https://mikro-orm.io/docs/metadata-providers.md#tsmorphmetadataprovider).

```
import { TsMorphMetadataProvider } from '@mikro-orm/reflection';

await MikroORM.init({
  metadataProvider: TsMorphMetadataProvider,
  // ...
});
```

Using `ReflectMetadataProvider` has some limitations, so be sure to read about them [here](https://mikro-orm.io/docs/metadata-providers.md#limitations-and-requirements).

One common gotcha with `reflect-metadata` is that you need to explicitly state the property type when using property initializer:

```
@Property()
createdAt: Date = new Date();
```

Without the explicit type, we would infer `Object` instead of `Date`, which would be most probably mapped to JSON column type (depends on driver).

## SqlEntityManager and MongoEntityManager[​](#sqlentitymanager-and-mongoentitymanager "Direct link to SqlEntityManager and MongoEntityManager")

In v4 the `core` package, where `EntityManager` and `EntityRepository` are defined, is not dependent on knex, and therefore it cannot have a method returning a `QueryBuilder`. You need to import the SQL flavour of the EM from the driver package to access the `createQueryBuilder()` method.

> The SQL flavour of EM is actually called `SqlEntityManager`, it is exported both under this name and under `EntityManager` alias, so you can just change the location from where you import.

```
import { EntityManager } from '@mikro-orm/mysql'; // or any other SQL driver package

const em: EntityManager;
const qb = await em.createQueryBuilder(...);
```

Same applies for the `aggregate()` method in mongo driver:

```
import { EntityManager } from '@mikro-orm/mongodb';

const em: EntityManager;
const ret = await em.aggregate(...);
```

> The mongo flavour of EM is actually called `MongoEntityManager`, it is exported both under this name and under `EntityManager` alias, so you can just change the location from where you import.

## Different default `pivotTable`[​](#different-default-pivottable "Direct link to different-default-pivottable")

Implementation of `UnderscoreNamingStrategy` and `EntityCaseNamingStrategy` `joinTableName()` method has changed. You can use `pivotTable` on the owning side of M<!-- -->:N<!-- --> relation to specify the table name manually.

Previously the table name did not respect property name, if one defined multiple M<!-- -->:N<!-- --> relations between same entities, there were conflicts and one would have to specify `pivotTable` name manually at least on one of them. With the new way, we can be sure that the table name won't conflict with other pivot tables.

Previously the name was constructed from 2 entity names as `entity_a_to_entity_b`, ignoring the actual property name. In v4 the name will be `entity_a_coll_name` in case of the collection property on the owning side being named `collName`.

## Changes in folder-based discovery (`entitiesDirs` removed)[​](#changes-in-folder-based-discovery-entitiesdirs-removed "Direct link to changes-in-folder-based-discovery-entitiesdirs-removed")

`entitiesDirs` and `entitiesDirsTs` were removed in favour of `entities` and `entitiesTs`, `entities` will be used as a default for `entitiesTs` (that is used when we detect `ts-node`).

`entities` can now contain mixture of paths to directories, globs pointing to entities, or references to the entities or instances of `EntitySchema`.

This basically means that all you need to change is renaming `entitiesDirs` to `entities`.

```
MikroORM.init({
  entities: ['dist/**/entities', 'dist/**/*.entity.js', FooBar, FooBaz],
  entitiesTs: ['src/**/entities', 'src/**/*.entity.ts', FooBar, FooBaz],
});
```

## Changes in `wrap()` helper, `WrappedEntity` interface and `Reference` wrapper[​](#changes-in-wrap-helper-wrappedentity-interface-and-reference-wrapper "Direct link to changes-in-wrap-helper-wrappedentity-interface-and-reference-wrapper")

Previously all the methods and properties of `WrappedEntity` interface were added to the entity prototype during discovery. In v4 there is only one property added: `__helper: WrappedEntity`. `WrappedEntity` has been converted to actual class.

`wrap(entity)` no longer returns the entity, now the `WrappedEntity` instance is being returned. It contains only public methods (`init`, `assign`, `isInitialized`, ...), if you want to access internal properties like `__meta` or `__em`, you need to explicitly ask for the helper via `wrap(entity, true)`.

Internal methods (with `__` prefix) were also removed from the `Reference` class, use `wrap(ref, true)` to access them.

Instead of interface merging with `WrappedEntity`, one can now use classic inheritance, by extending `BaseEntity` exported from `@mikro-orm/core`. If you do so, `wrap(entity)` will return your entity.

## Removed `flush` parameter from `persist()` and `remove()` methods[​](#removed-flush-parameter-from-persist-and-remove-methods "Direct link to removed-flush-parameter-from-persist-and-remove-methods")

`flush` param is removed, both `persist` and `remove` methods are synchronous and require explicit flushing, possibly via fluent interface call.

```
// before
await em.persist(jon, true);
await em.remove(Author, jon, true);

// after
await em.persist(jon).flush();
await em.remove(jon).flush();
```

## `remove()` method requires entity instances[​](#remove-method-requires-entity-instances "Direct link to remove-method-requires-entity-instances")

The `em.remove()` method originally allowed to pass either entity instance, or a condition. When one passed a condition, it was firing a native delete query, without handling transactions or hooks.

In v4, the method is now simplified and works only with entity instances. Use `em.nativeDelete()` explicitly if you want to fire a delete query instead of letting the `UnitOfWork` doing its job.

```
// before
await em.remove(Author, 1); // fires query directly

// after
await em.nativeDelete(Author, 1);
```

> `em.removeEntity()` has been removed in favour of `em.remove()` (that now has almost the same signature).

## Type safe references[​](#type-safe-references "Direct link to Type safe references")

EM now returns `Loaded<T, P>` instead of the entity (`T`). This type automatically adds synchronous method `get()` that returns the entity (for references) or array of entities (for collections).

`Reference.get()` is now available only with correct `Loaded` type hint and is used as a sync getter for the entity, just like `unwrap()`. You can use `Reference.load(prop)` for the original `get()` method functionality.

`em.find()` and similar methods now have two type arguments, due to TypeScript not supporting partial type inference, when you specify the `T` explicitly (without also explicitly specifying the load hint), the inference will not work. This use case was mainly for usage without classes (interfaces + `EntitySchema`) - in that case it is now supported to pass actual instance of `EntitySchema` as the first parameter to these methods, that will allow correct type inference:

```
const author = await em.findOne(AuthorSchema, { ... }, ['books']);
console.log(author.books.get()); // `get()` is now inferred correctly
```

## Custom types are now type safe[​](#custom-types-are-now-type-safe "Direct link to Custom types are now type safe")

Generic `Type` class has now two type arguments - the input and output types. Input type defaults to `string`, output type defaults to the input type.

You might need to explicitly provide the types if your methods are strictly typed.

## Custom type serialization[​](#custom-type-serialization "Direct link to Custom type serialization")

Custom types used to be serialized to the database value. In v4, the runtime value is used by default. Implement custom `toJSON()` method if you need to customize this.

## Property `default` and `defaultRaw`[​](#property-default-and-defaultraw "Direct link to property-default-and-defaultraw")

Previously the `default` option of properties was used as is, so we had to wrap strings in quotes (e.g. `@Property({ default: "'foo bar'" })`).

In v4 the `default` is typed as `string | number | boolean | null` and when used with string value, it will be automatically quoted.

To use SQL functions we now need to use `defaultRaw`: `@Property({ defaultRaw: 'now()' })`.

## `autoFlush` option has been removed[​](#autoflush-option-has-been-removed "Direct link to autoflush-option-has-been-removed")

Also `persistLater()` and `removeLater()` methods are deprecated. Use `persist()` or `remove` respectively.

## `IdEntity`, `UuidEntity` and `MongoEntity` interfaces are removed[​](#identity-uuidentity-and-mongoentity-interfaces-are-removed "Direct link to identity-uuidentity-and-mongoentity-interfaces-are-removed")

They were actually never needed.

## MongoDB driver is no longer the default[​](#mongodb-driver-is-no-longer-the-default "Direct link to MongoDB driver is no longer the default")

You need to specify the platform type either via `type` option or provide the driver implementation via `driver` option.

Available platforms types: `[ 'mongo', 'mysql', 'mariadb', 'postgresql', 'sqlite' ]`

## Removed configuration `discovery.tsConfigPath`[​](#removed-configuration-discoverytsconfigpath "Direct link to removed-configuration-discoverytsconfigpath")

Removed as it is no longer needed, it was used only for `TsMorphMetadataProvider`, when the `entitiesDirsTs` were not explicitly provided. In v4, this is no longer needed, as ts-morph discovery will use `d.ts` files instead, that should be located next to the compiled entities.

## Changes in query highlighting[​](#changes-in-query-highlighting "Direct link to Changes in query highlighting")

Previously Highlight.js was used to highlight various things in the CLI, like SQL and mongo queries, or migrations or entities generated via CLI. While the library worked fine, it was causing performance issues mainly for those bundling via webpack and using lambdas, as the library was huge.

In v4 highlighting is disabled by default, and there are 2 highlighters you can optionally use (you need to install them first).

```
import { SqlHighlighter } from '@mikro-orm/sql-highlighter';

MikroORM.init({
  highlighter: new SqlHighlighter(),
  // ...
});
```

For MongoDB, you can use `@mikro-orm/mongo-highlighter`.