# FormatHandler Interface in Convert: A Complete Guide to Building Custom File Converters

> Master the FormatHandler interface in p2r3/convert. Build custom file converters with automatic discovery, prioritization, and chaining. A complete guide.

- Repository: [p2r3/convert](https://github.com/p2r3/convert)
- Tags: deep-dive
- Published: 2026-02-19

---

**The `FormatHandler` interface in the p2r3/convert repository defines the contract that every conversion plugin must implement, enabling automatic discovery, prioritization, and chaining of format-specific transformations.**

The `FormatHandler` interface serves as the architectural backbone of the convert project, allowing developers to extend the engine with new file format support without modifying core logic. Located in [`src/FormatHandler.ts`](https://github.com/p2r3/convert/blob/main/src/FormatHandler.ts), this TypeScript interface standardizes how handlers declare their supported formats, process incoming files, and integrate into the conversion pipeline.

## What Is the FormatHandler Interface?

The `FormatHandler` interface establishes a strict contract between the convert engine and individual format implementations. By implementing this interface, developers ensure their handlers can be automatically registered, discovered, and executed by the traversal graph system.

### Core Properties and Methods

The interface requires specific properties and methods that the engine uses to route files through the conversion pipeline:

- **`format: FileFormat`** — A `FileFormat` object (defined in [`src/CommonFormats.ts`](https://github.com/p2r3/convert/blob/main/src/CommonFormats.ts)) containing the MIME type, file extensions, and display title the handler processes.
- **`process(input: FileData, opts?: any): Promise<FileData>`** — The core conversion method that accepts a `FileData` blob, performs the transformation, and returns a promise resolving to the converted output.
- **`supported?: string[]`** — Optional array of additional MIME types or extensions the handler can accept beyond its primary format.
- **`priority?: number`** — Optional numeric hint used by [`src/TraversionGraph.ts`](https://github.com/p2r3/convert/blob/main/src/TraversionGraph.ts) to resolve conflicts when multiple handlers can process the same input format.

## How FormatHandler Powers the Convert Engine

The convert engine uses the `FormatHandler` interface to decouple format-specific logic from the core conversion pipeline. This architecture enables automatic handler discovery and intelligent pathfinding between formats.

### Handler Registration in src/handlers/index.ts

All concrete implementations aggregate in [`src/handlers/index.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/index.ts), where the engine collects available handlers into a single array:

```typescript
// src/handlers/index.ts
const handlers: FormatHandler[] = [
  new vtfHandler(),
  new threejsHandler(),
  new pandocHandler(),
  /* … additional handlers … */
];

```

This registration pattern allows the engine to iterate over all available handlers without importing each implementation individually.

### Discovery via TraversionGraph

During application startup in [`src/main.ts`](https://github.com/p2r3/convert/blob/main/src/main.ts), the handler array feeds into the `TraversionGraph` class defined in [`src/TraversionGraph.ts`](https://github.com/p2r3/convert/blob/main/src/TraversionGraph.ts):

```typescript
// src/main.ts (excerpt)
const allOptions = handlers.map(h => ({ format: h.format, handler: h }));
const graph = new TraversionGraph();
graph.init(supportedFormatCache, allOptions, strictCategories);

```

The graph constructs a directed acyclic graph where nodes represent `FileFormat` objects and edges represent available transformations. The `priority` property on each `FormatHandler` helps resolve paths when multiple handlers can perform the same conversion.

### Execution Pipeline

When a user initiates a conversion, the engine queries the graph for the shortest path from source to target format. It then iteratively invokes each handler's `process` method, passing the `FileData` output from one handler as the input to the next. This chaining continues until the final format emerges.

## Implementing a Custom FormatHandler

Creating a new format handler requires implementing the interface and registering the class in the handler index.

### Minimal Custom Handler Example

This example demonstrates a handler that converts a hypothetical `.ex` format to text:

```typescript
// src/handlers/example.ts
import type { FileData, FileFormat, FormatHandler } from '../FormatHandler.js';

const exampleFormat: FileFormat = {
  mime: 'application/example',
  ext: ['.ex'],
  title: 'Example format',
};

export class ExampleHandler implements FormatHandler {
  format = exampleFormat;

  async process(input: FileData): Promise<FileData> {
    // Conversion logic here
    const convertedData = new Uint8Array(/* transformation result */);
    
    return {
      name: input.name.replace(/\.ex$/, '.txt'),
      mime: 'text/plain',
      data: convertedData,
    };
  }
}

```

After implementation, export the handler in [`src/handlers/index.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/index.ts) to activate it.

### Using Handlers Through the Engine

Client code typically interacts with handlers indirectly through the main conversion API:

```typescript
import { convertFile } from './main.js';

const input: FileData = {
  name: 'example.ex',
  mime: 'application/example',
  data: await file.arrayBuffer(),
};

convertFile(input).then(output => {
  // Output contains the final FileData after traversing 
  // all necessary FormatHandlers in the conversion chain
  console.log(`Converted to ${output.mime}`);
});

```

## Summary

- The `FormatHandler` interface in [`src/FormatHandler.ts`](https://github.com/p2r3/convert/blob/main/src/FormatHandler.ts) defines the mandatory contract for all conversion plugins in the p2r3/convert repository.
- Required members include the `format` property describing supported types and the `process` method performing the actual transformation.
- Optional properties like `priority` and `supported` enable fine-tuning of handler selection when multiple paths exist.
- The `TraversionGraph` class uses these handlers to build a conversion graph, automatically discovering routes between any supported formats.
- New handlers require only implementing the interface and registering in [`src/handlers/index.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/index.ts), requiring no changes to core engine code.

## Frequently Asked Questions

### What is the difference between FileFormat and FormatHandler?

`FileFormat` is a data structure defined in [`src/CommonFormats.ts`](https://github.com/p2r3/convert/blob/main/src/CommonFormats.ts) that describes static properties of a file type, including MIME type, extensions, and display name. `FormatHandler` is the interface that defines active behavior for converting to or from that format, including the `process` method that performs transformations. A single `FormatHandler` references one `FileFormat` through its `format` property.

### How does convert decide which FormatHandler to use?

The `TraversionGraph` class in [`src/TraversionGraph.ts`](https://github.com/p2r3/convert/blob/main/src/TraversionGraph.ts) builds a directed graph of all possible conversions during initialization. When multiple handlers can perform the same conversion, the system consults the optional `priority` property on each `FormatHandler`, selecting the handler with the highest priority value. If priorities are equal, the graph uses internal heuristics to determine the optimal path.

### Can I chain multiple FormatHandlers together?

Yes, chaining is the primary conversion mechanism in the convert engine. When converting between formats where no direct handler exists, the `TraversionGraph` calculates the shortest path through intermediate formats. The engine then executes each handler's `process` method sequentially, passing the `FileData` output from one handler as the input to the next until reaching the target format.

### Where should I register a new FormatHandler implementation?

All handlers must be instantiated and added to the `handlers` array in [`src/handlers/index.ts`](https://github.com/p2r3/convert/blob/main/src/handlers/index.ts). This central registration file imports each handler class, creates an instance, and exports the aggregated array. The main application imports this array in [`src/main.ts`](https://github.com/p2r3/convert/blob/main/src/main.ts) to initialize the `TraversionGraph`, making the new handler automatically available for conversion path discovery.