# How Mermaid's detectType.ts Diagram Detection System Works and How to Register Custom Detectors

> Explore Mermaid's detectType.ts diagram detection system. Learn how it matches diagrams and how to register custom detectors to extend its capabilities.

- Repository: [mermaid-js/mermaid](https://github.com/mermaid-js/mermaid)
- Tags: internals
- Published: 2026-02-23

---

**Mermaid determines which diagram renderer to use by executing a registry of detector functions defined in [`detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/detectType.ts), returning the first matching diagram key, and you can extend this pipeline by registering custom detectors via `addDetector()` or `registerLazyLoadedDiagrams()` before initialization.**

The **mermaid-js/mermaid** library implements a modular architecture that delegates diagram identification to a pluggable **diagram detection system**. Central to this mechanism is [`packages/mermaid/src/diagram-api/detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/detectType.ts), which cleans input text, iterates over registered matchers, and lazy-loads implementations on demand. By leveraging the public detector registry APIs, you can teach Mermaid to recognize entirely new syntaxes without modifying core library code.

## How Mermaid Detects Diagram Types

The detection flow follows a strict precedence-based pipeline. When `detectType()` is invoked, it first sanitizes the input to remove metadata that could interfere with pattern matching.

**Pre-processing** occurs at lines 36-40 of [`detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/detectType.ts), where the system strips front-matter, `%%{initialize…}` directives, and comments:

```ts
text = text
  .replace(frontMatterRegex, '')
  .replace(directiveRegex, '')
  .replace(anyCommentRegex, '\n');

```

**Detector iteration** happens next (lines 41-46). The function walks the global `detectors` object and executes each `detector(text, config)` function until one returns a truthy value:

```ts
for (const [key, { detector }] of Object.entries(detectors)) {
  if (detector(text, config)) return key;
}

```

The `key` (e.g., `"flowchart-elk"`, `"pie"`) is immediately returned as the diagram type. If no detector matches, the system throws an `UnknownDiagramError` (lines 48-50). Later, when the diagram renders, `getDiagramLoader(key)` retrieves the optional loader function to import the implementation on demand (lines 80-82).

## The Detector Registry Architecture

The registry is a plain object exported from [`detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/detectType.ts):

```ts
export const detectors: Record<string, DetectorRecord> = {};

```

Built-in diagrams populate this registry during initialization via [`packages/mermaid/src/diagram-api/diagram-orchestration.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/diagram-orchestration.ts). This file imports individual detectors and calls `registerLazyLoadedDiagrams()` with specific ordering to ensure more specific matchers execute before generic ones:

```ts
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
// ...
registerLazyLoadedDiagrams(flowchartElk, mindmap, architecture);

```

## Registering Custom Diagram Detectors

You can inject custom logic into the registry using two primary APIs, depending on whether your diagram implementation requires lazy loading.

### Simple Registration with addDetector

For lightweight diagrams already bundled in your application, use `addDetector()` to register a synchronous detector and optional loader:

```ts
import { addDetector } from '@mermaid-js/mermaid/dist/diagram-api/detectType.js';
import type { DiagramDetector, DiagramLoader } from '@mermaid-js/mermaid/dist/diagram-api/types.js';

// Detector function returns true when text matches your syntax
const myDetector: DiagramDetector = (txt) => /^\s*mygraph/.test(txt);

// Optional: Lazy loader for the diagram implementation
const myLoader: DiagramLoader = async () => {
  const { diagram } = await import('./myDiagram.js');
  return { id: 'my-diagram', diagram };
};

// Register to the global detectors map (line 72)
addDetector('my-diagram', myDetector, myLoader);

```

### Lazy-Loaded Registration with registerLazyLoadedDiagrams

For heavy diagram implementations, bundle the definition using `ExternalDiagramDefinition` and register via `registerLazyLoadedDiagrams()` (lines 66-70):

```ts
import { registerLazyLoadedDiagrams } from '@mermaid-js/mermaid/dist/diagram-api/detectType.js';
import type { ExternalDiagramDefinition } from '@mermaid-js/mermaid/dist/diagram-api/types.js';

const myDiagram: ExternalDiagramDefinition = {
  id: 'my-diagram',
  detector: (txt) => /^\s*mygraph/.test(txt),
  loader: async () => {
    const { diagram } = await import('./myDiagram.js');
    return { id: 'my-diagram', diagram };
  },
};

// Order matters: register specific detectors before generic ones
registerLazyLoadedDiagrams(myDiagram);

```

### Registration Timing Requirements

Registration must complete **before** Mermaid parses any diagram text. Invoke these helpers early in your application lifecycle, such as immediately after importing the Mermaid library but before calling `mermaid.initialize()` or `mermaid.run()`. If registering within a plugin architecture, ensure your module executes prior to the core `addDiagrams()` function in [`diagram-orchestration.ts`](https://github.com/mermaid-js/mermaid/blob/main/diagram-orchestration.ts).

## Complete Working Example: Custom "Gantt-Lite" Detector

The following implementation demonstrates a custom diagram that triggers on the `gantt-lite` keyword and lazy-loads its renderer:

```ts
// myGanttLiteDetector.ts
import type { ExternalDiagramDefinition } from '@mermaid-js/mermaid/dist/diagram-api/types.js';
import { registerLazyLoadedDiagrams } from '@mermaid-js/mermaid/dist/diagram-api/detectType.js';

// 1. Define the detector logic
const detector = (txt: string) => /^\s*gantt-lite/.test(txt);

// 2. Define the async loader
const loader = async () => {
  const { diagram } = await import('./ganttLiteDiagram.js');
  return { id: 'gantt-lite', diagram };
};

// 3. Bundle as ExternalDiagramDefinition
const ganttLite: ExternalDiagramDefinition = { 
  id: 'gantt-lite', 
  detector, 
  loader 
};

// 4. Register before Mermaid initializes
registerLazyLoadedDiagrams(ganttLite);

```

Once registered, any Mermaid code block beginning with `gantt-lite` will trigger your detector, execute the loader to fetch [`ganttLiteDiagram.js`](https://github.com/mermaid-js/mermaid/blob/main/ganttLiteDiagram.js), and render using your custom logic.

## Core Source Files and Type Definitions

Understanding these files is essential for advanced customization:

- **[`packages/mermaid/src/diagram-api/detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/detectType.ts)** – Contains `detectType()`, the `detectors` registry, `addDetector()`, and `registerLazyLoadedDiagrams()` (lines 1-82).
- **[`packages/mermaid/src/diagram-api/types.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/types.ts)** – Defines TypeScript interfaces: `DiagramDetector`, `DiagramLoader`, and `ExternalDiagramDefinition`.
- **[`packages/mermaid/src/diagram-api/diagram-orchestration.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/diagram-orchestration.ts)** – Orchestrates built-in detector registration order and lazy-loading configuration.
- **[`packages/mermaid/src/diagrams/flowchart/elk/detector.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagrams/flowchart/elk/detector.ts)** – Example detector that mutates configuration (`config.layout = 'elk'`) during detection.
- **[`packages/mermaid/src/mermaid.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/mermaid.ts)** – Public entry point consuming `detectType()` during the rendering pipeline.

## Summary

- **Detection Flow**: `detectType()` sanitizes input, iterates the `detectors` registry in insertion order, and returns the first matching key or throws `UnknownDiagramError`.
- **Registry**: A global `Record<string, DetectorRecord>` stored in [`detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/detectType.ts), populated by [`diagram-orchestration.ts`](https://github.com/mermaid-js/mermaid/blob/main/diagram-orchestration.ts) for built-ins.
- **Registration API**: Use `addDetector(key, detector, loader?)` for eager registration, or `registerLazyLoadedDiagrams(...defs)` for bundled, ordered registration with lazy loading.
- **Extensibility**: Implement `DiagramDetector` to recognize syntax and `DiagramLoader` to import implementations, registering them early in the application lifecycle.

## Frequently Asked Questions

### What happens if multiple detectors match the input text?

The first registered detector returning a truthy value wins. Because [`detectType.ts`](https://github.com/mermaid-js/mermaid/blob/main/detectType.ts) iterates with `for...of` over `Object.entries(detectors)` (line 41), registration order is critical. Register more specific detectors before generic ones to ensure correct routing.

### Can custom detectors modify the Mermaid configuration?

Yes. The `DiagramDetector` function signature includes a `config` parameter (`(text: string, config?: MermaidConfig) => boolean`), allowing detectors to mutate configuration values before rendering. For example, the built-in flowchart-elk detector in [`packages/mermaid/src/diagrams/flowchart/elk/detector.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagrams/flowchart/elk/detector.ts) sets `config.layout = 'elk'` when it detects ELK-specific syntax.

### What is the difference between addDetector and registerLazyLoadedDiagrams?

**`addDetector()`** registers a single detector and optional loader directly to the global map (line 72), suitable for simple extensions. **`registerLazyLoadedDiagrams()`** accepts multiple `ExternalDiagramDefinition` objects, iterates them in order, and internally calls `addDetector()` for each (lines 66-70), providing a cleaner API for registering multiple lazy-loaded diagrams with guaranteed precedence.

### Where should I place custom detector registration code?

Execute registration code immediately after importing Mermaid but before calling `mermaid.init()` or `mermaid.run()`. For browser environments, place your registration script after the Mermaid bundle but before any render calls. For Node.js or bundled applications, ensure your detector module runs before the main `addDiagrams()` function executes in [`diagram-orchestration.ts`](https://github.com/mermaid-js/mermaid/blob/main/diagram-orchestration.ts).