Skip to main content
Version: 7.0 (next)

Folder-based Discovery

Instead of explicitly listing all entities, you can use glob patterns to discover entities automatically based on file naming conventions.

Configuration

mikro-orm.config.ts
import { defineConfig } from '@mikro-orm/sqlite';

export default defineConfig({
// Glob patterns for compiled JavaScript files
entities: ['dist/**/*.entity.js'],
// Glob patterns for TypeScript source files (used in development)
entitiesTs: ['src/**/*.entity.ts'],
// ...
});

How it works

  1. When running from TypeScript (e.g., via tsx, or in tests), MikroORM uses entitiesTs patterns
  2. When running from compiled JavaScript, MikroORM uses entities patterns
  3. Files matching the patterns are dynamically imported and scanned for entity definitions

It is important that entities points to the compiled JS files, and entitiesTs points to the TS source files. You should not mix those.

File naming conventions

A common convention is to use the .entity.ts suffix:

src/
├── modules/
│ ├── user/
│ │ └── user.entity.ts
│ ├── article/
│ │ ├── article.entity.ts
│ │ └── tag.entity.ts
│ └── common/
│ └── base.entity.ts
└── mikro-orm.config.ts

Glob patterns

The paths are resolved using native Node.js glob, so you can use standard globbing patterns:

const orm = await MikroORM.init({
// All .entity.js files in dist folder recursively
entities: ['./dist/**/*.entity.js'],

// Multiple patterns
entities: ['./dist/modules/**/*.entity.js', './dist/shared/**/*.entity.js'],

// Negative patterns to exclude files
entities: ['./dist/**/*.entity.js', '!./dist/**/*.test.entity.js'],
});
Brace expansion

Native Node.js glob does not support brace expansion patterns like src/{entities,modules}/*.ts. If you need this feature, use tinyglobby directly:

import { glob } from 'tinyglobby';

export default defineConfig({
entities: await glob(['src/{entities,modules}/*.ts']),
});

Debugging discovery

If you are experiencing problems with folder-based discovery, use the mikro-orm debug CLI command to check what paths are actually being used:

npx mikro-orm debug

This will show you:

  • Which configuration file is being loaded
  • The resolved entity paths
  • Which entities were discovered

Explicit vs Folder-based Discovery

AspectExplicit (entities: [User])Folder-based (entities: ['**/*.entity.js'])
Setup complexityMore codeLess code
RefactoringIDE-supportedManual pattern updates
Build toolsWorks everywhereMay need configuration
PerformanceFaster startupSlightly slower (file scanning)
Error detectionCompile-timeRuntime

When to use explicit references

  • Small to medium projects
  • When using bundlers like webpack or esbuild
  • When you want maximum IDE support and type safety
  • When using defineEntity (recommended approach)

When to use folder-based discovery

  • Large projects with many entities
  • When using decorator-based entities with ts-morph
  • When entities are spread across many modules
  • When you want to avoid updating config when adding new entities

Synchronous initialization limitation

When using the synchronous new MikroORM() constructor instead of MikroORM.init(), folder-based discovery is not supported:

// This works - async initialization supports folder-based discovery
const orm = await MikroORM.init({
entities: ['dist/**/*.entity.js'],
});

// This does NOT work - must use explicit entity references
const orm = new MikroORM({
entities: ['dist/**/*.entity.js'],
// use explicit references only with sync init
// entities: [User, Article],
});

Multiple entity locations

You can combine multiple patterns and explicit references:

import { BaseEntity } from './entities/base.entity.js';

export default defineConfig({
entities: [
BaseEntity, // explicit reference
'dist/modules/**/*.entity.js', // glob pattern
],
entitiesTs: [
BaseEntity,
'src/modules/**/*.entity.ts',
],
});

This is useful when you have base entities that need to be loaded first, or when mixing discovery approaches.