# Source: https://mikro-orm.io/docs/custom-driver.md

# Creating Custom Driver

If you want to use database that is not currently supported, you can implement your own driver. To do so, you will need to design 4 classes:

## Platform[​](#platform "Direct link to Platform")

Platform is a class that provides information about available features of given driver:

```
import { Platform } from '@mikro-orm/core';

export class MyCustomPlatform extends Platform {

  protected abstract schemaHelper: MyCustomSchemaHelper;

  // here you can override default settings
  usesPivotTable(): boolean;
  supportsTransactions(): boolean;
  supportsSavePoints(): boolean;
  getNamingStrategy(): { new (): NamingStrategy; };
  getIdentifierQuoteCharacter(): string;
  getParameterPlaceholder(index?: number): string;
  usesReturningStatement(): boolean;
  normalizePrimaryKey<T = number | string>(data: IPrimaryKey): T;
  denormalizePrimaryKey(data: IPrimaryKey): IPrimaryKey;
  getSerializedPrimaryKeyField(field: string): string;

}
```

## SchemaHelper[​](#schemahelper "Direct link to SchemaHelper")

Part of platform is a `SchemaHelper`, that provides information about how to build schema.

```
import { SchemaHelper } from '@mikro-orm/core';

export class MyCustomSchemaHelper extends SchemaHelper {

  // here you can override default settings
  getIdentifierQuoteCharacter(): string;
  getSchemaBeginning(): string;
  getSchemaEnd(): string;
  getSchemaTableEnd(): string;
  getAutoIncrementStatement(meta: EntityMetadata): string;
  getPrimaryKeySubtype(meta: EntityMetadata): string;
  getTypeDefinition(prop: EntityProperty, types?: Record<string, string>, lengths?: Record<string, number>): string;
  getUnsignedSuffix(prop: EntityProperty): string;
  supportsSchemaConstraints(): boolean;
  supportsSchemaMultiAlter(): boolean;
  supportsSequences(): boolean;
  quoteIdentifier(field: string): string;
  dropTable(meta: EntityMetadata): string;
  indexForeignKeys(): boolean;

}
```

## Connection[​](#connection "Direct link to Connection")

Next part is connection wrapper, that will be responsible for querying the database:

```
import { Connection } from '@mikro-orm/core';

export class MyCustomConnection extends Connection {

  // implement abstract methods
  connect(): Promise<void>;
  isConnected(): Promise<boolean>;
  close(force?: boolean): Promise<void>;
  getDefaultClientUrl(): string;
  execute(query: string, params?: any[], method?: 'all' | 'get' | 'run'): Promise<QueryResult | any | any[]>;

}
```

## Driver[​](#driver "Direct link to Driver")

Last part is driver, that is responsible for using the connection to persist changes to database. If you are building SQL driver, it might be handy to extend `AbstractSqlDriver`, if not, extend `DatabaseDriver` abstract class.

If you want to have absolute control, you can implement the whole driver yourself via `IDatabaseDriver` interface.

```
import { DatabaseDriver } from '@mikro-orm/core';

export class MyCustomDriver extends DatabaseDriver {

  // initialize connection and platform
  protected readonly connection = new MyCustomConnection(this.config);
  protected readonly platform = new MyCustomPlatform;

  // and implement abstract methods
  find<T extends AnyEntity>(entityName: string, where: FilterQuery<T>, populate?: string[], orderBy?: Record<string, QueryOrder>, limit?: number, offset?: number): Promise<T[]>;
  findOne<T extends AnyEntity>(entityName: string, where: FilterQuery<T> | string, populate: string[]): Promise<T | null>;
  nativeInsert<T extends AnyEntityType<T>>(entityName: string, data: EntityData<T>): Promise<QueryResult>;
  nativeUpdate<T extends AnyEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey, data: EntityData<T>): Promise<QueryResult>;
  nativeDelete<T extends AnyEntity>(entityName: string, where: FilterQuery<T> | IPrimaryKey): Promise<QueryResult>;
  count<T extends AnyEntity>(entityName: string, where: FilterQuery<T>): Promise<number>;

}
```