Borewit/music-metadata

Metadata parser for audio and video media files. Supports file and stream inputs in Node.js and browser environments, extracting format, tag, and duration information.

TypeScript

1,330

3,733 commits

updated Oct 12, 2026

See the code

README

CI NPM version npm downloads codecov Codacy Badge CodeQL DeepScan grade Known Vulnerabilities

music-metadata

logo

Key features:

  • Comprehensive Format Support: Supports popular audio formats like MP3, MP4, FLAC, Ogg, WAV, AIFF, and more.
  • Extensive Metadata Extraction: Extracts detailed metadata, including ID3v1, ID3v2, APE, Vorbis, and iTunes/MP4 tags.
  • Streaming Support: Efficiently handles large audio files by reading metadata from streams, making it suitable for server-side and browser-based applications.
  • Promise-Based API: Provides a modern, promise-based API for easy integration into asynchronous workflows.
  • Cross-Platform: Works in both Node.js and browser environments with the help of bundlers like Webpack or Rollup.

The music-metadata module is ideal for developers working on media applications, music players, or any project that requires access to detailed audio file metadata.

Compatibility

Module: version 8 migrated from CommonJS to pure ECMAScript Module (ESM). The distributed JavaScript codebase targets ECMAScript 2023 (14th Edition).

[!NOTE] See also CommonJS backward Compatibility

This module requires a Node.js ≥ 22 engine. It can also be used in a browser environment when bundled with a module bundler.

Support the Project

If you find this project useful and would like to support its development, consider sponsoring or contributing:

Features

Support for audio file types

Audio formatDescriptionLogo
AIFF / AIFF-CAudio Interchange File FormatApple rainbow logo
AACADTS / Advanced Audio CodingAAC logo
APEMonkey's AudioMonkey's Audio logo
ASFAdvanced Systems Format
BWFExtended WAV format for broadcast and archiving
CAFCore Audio File FormatApple rainbow logo
DSDIFFPhilips DSDIFFDSD logo
DSFSony's DSD Stream FileDSD logo
FLACFree Lossless Audio CodecFLAC logo
MP2MPEG-1 Audio Layer II (predecessor to MP3)
MatroskaMatroska (EBML), mka, mkvMatroska logo
MP3MPEG-1 / MPEG-2 Audio Layer IIIMP3 logo
MPCMusepack SV7musepack logo
MPEG 4mp4, m4a, m4vmpeg 4 logo
OggOpen container formatOgg logo
OpusLow-latency, high-quality codec for speech and musicOpus logo
SpeexOpen-source speech codec optimized for VoIPSpeex logo
TheoraOpen video compression format (typically paired with Ogg)Theora logo
VorbisVorbis audio compressionVorbis logo
WAVUncompressed PCM audio in RIFF container
WebMWebMMatroska logo
WVWavPackWavPack logo
WMAWindows Media AudioWindows Media logo

Supported tag headers

Following tag header formats are supported:

Following lyric formats are supported:

  • LRC
  • Synchronized lyrics (SYLT)
  • Unsynchronized lyrics (USLT)

Support for MusicBrainz tags as written by Picard. ReplayGain tags are supported.

Audio format & encoding details

Support for encoding / format details:

Online demo's

Used by around 50k+ GitHub projects.

Usage

Installation

Install using npm:

npm install music-metadata

or using yarn:

yarn add music-metadata

API Documentation

Overview

Node.js specific functions to read an audio file or stream:

  1. File Parsing: Parse audio files directly from the filesystem using the parseFile function
  2. Stream Parsing: Parse audio metadata from a Node.js Readable stream using the parseStream function.

Cross-platform functions available to read an audio file or stream:

There are multiple ways to parse (read) audio tracks:

  1. Web Stream Parsing: Parse audio data from a web-compatible ReadableStream using the parseWebStream function.
  2. Blob Parsing: Parse audio metadata from a (Web API) Blob or File using the parseBlob function.
  3. Buffer Parsing: Parse audio metadata from a Uint8Array or Buffer using the parseBuffer function.
  4. Tokenizer Parsing: Use a custom or third-party strtok3 ITokenizer to parse using the parseFromTokenizer function.

[!NOTE] Direct file access in Node.js is generally faster because it can 'jump' to various parts of the file without reading intermediate data.

Node.js specific functions

These functions use Node.js-specific APIs, making them incompatible with browser-based JavaScript engines.

parseFile function

The parseFile function is intended for extracting metadata from audio files on the local filesystem in a Node.js environment. It reads the specified file, parses its audio metadata, and returns a promise that resolves with this information.

Syntax
parseFile(filePath: string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • filePath: string

    The path to the media file from which metadata should be extracted. This should be a valid path to an audio file on the local filesystem.

  • options: IOptions (optional)

    An optional configuration object that allows customization of the parsing process. These options can include whether to calculate the file's duration, skip embedded cover art, or other parsing behaviors.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing metadata about the audio file. The metadata includes details such as the file format, codec, duration, bit rate, and any embedded tags like album, artist, or track information.

Usage Notes
  • This function is Node.js-only and relies on Node.js-specific APIs to access the filesystem.

  • For browser environments, consider using the parseBlob to parse File object objects.

Example:

The following example demonstrates how to use the parseFile function to read metadata from an audio file:

import { parseFile } from 'music-metadata';
import { inspect } from 'node:util';

(async () => {
  try {
    const filePath = 'test/samples/MusicBrainz - Beth Hart - Sinner\'s Prayer [id3v2.3].V2.mp3';
    const metadata = await parseFile(filePath);

    // Output the parsed metadata to the console in a readable format
    console.log(inspect(metadata, { showHidden: false, depth: null }));
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseStream function

The parseStream function is used to parse metadata from an audio track provided as a Node.js Readable stream. This is particularly useful for processing audio data that is being streamed or piped from another source, such as a web server or file system.

Syntax:
parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters:
  • stream: Readable:

    The Node.js Readable stream from which the audio data is read. This stream should provide the raw audio data to be analyzed.

  • fileInfo: IFileInfo (optional)

    An object containing file-related information or a string representing the MIME-type of the audio stream. The fileInfo parameter can help the parser to correctly identify the audio format and may include:

    • mimeType: A string representing the MIME-type (e.g., audio/mpeg).

      If provided, it is assumed the streamed file content is to be the MIME-type. If not provided, the parser will attempt to determine the format based on the content of the stream.

    • size: The total size of the audio stream in bytes (useful for streams with a known length).

    • path: A string representing the file path or filename, which can also assist in determining the format.

  • options: IOptions (optional)

    An optional object containing additional parsing options. These options allow you to customize the parsing process, such as whether to calculate the duration or skip cover art extraction.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing detailed metadata about the audio stream. This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.

Usage Notes
  • This function is only available in Node.js environments, as it relies on the Node.js stream API.
Example:

The following example demonstrates how to use the parseStream function to read metadata from an audio stream:

import { parseStream } from 'music-metadata';
import { createReadStream } from 'fs';

(async () => {
  try {
    // Create a readable stream from a file
    const audioStream = createReadStream('path/to/audio/file.mp3');

    // Parse the metadata from the stream
    const metadata = await parseStream(audioStream, { mimeType: 'audio/mpeg'});

    // Log the parsed metadata
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

Cross-platform functions

These functions are designed to be cross-platform, meaning they can be used in both Node.js and web browsers.

parseWebStream function

The parseWebStream function is used to extract metadata from an audio track provided as a web-compatible ReadableStream. This function is ideal for applications running in web environments, such as browsers, where audio data is streamed over the network or read from other web-based sources.

Syntax
parseWebStream(webStream: ReadableStream<Uint8Array>, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • webStream: ReadableStream<Uint8Array>

    A ReadableStream that provides the audio data to be parsed. This stream should emit Uint8Array chunks, representing the raw audio data.

  • fileInfo: IFileInfo (optional)

    An object containing file-related information or a string representing the MIME-type of the audio stream. The fileInfo parameter can help the parser to correctly identify the audio format and may include:

    • mimeType: A string representing the MIME-type (e.g., audio/mpeg).

      If provided, it is assumed the streamed file content is to be the MIME-type. If not provided, the parser will attempt to determine the format based on the content of the stream.

    • size: The total size of the audio stream in bytes (useful for streams with a known length).

    • path: A string representing the file path or filename, which can also assist in determining the format.

  • options: IOptions (optional)

    An optional object containing additional parsing options. These options allow you to customize the parsing process, such as whether to calculate the duration or skip cover art extraction.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing detailed metadata about the audio stream. This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.

Example

Here’s an example of how to use the parseWebStream function to extract metadata from an audio stream in a web application:

import { parseWebStream } from 'music-metadata';

(async () => {
  try {
    // Fetch the audio file
    const response = await fetch('https://github.com/Borewit/test-audio/raw/refs/heads/master/Various%20Artists%20-%202008%20-%20netBloc%20Vol%2013%20-%20Color%20in%20a%20World%20of%20Monochrome%20%5BAAC-40%5D/1.02.%20Solid%20Ground.m4a');

    // Extract the Content-Length header and convert it to a number
    const contentLength = response.headers.get('Content-Length');
    const size = contentLength ? parseInt(contentLength, 10) : undefined;

    // Parse the metadata from the web stream
    const metadata = await parseWebStream(response.body, {
      mimeType: response.headers.get('Content-Type'),
      size // Important to pass the content-length
    });

    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

The example uses the fetch API to retrieve an audio file from a URL. The response.body provides a ReadableStream that is then passed to parseWebStream.

parseBlob function

Parses metadata from an audio file represented as a Blob. This function reads slices of the Blob and supports both browser File objects and Node.js Blob objects.

Syntax
parseBlob(blob: Blob, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • blob: Blob

    The Blob object containing the audio data to be parsed. This can be a File selected by the user or a Blob containing audio data. The Blob size and MIME type are passed to the parser.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio file.

Example
import { parseBlob } from 'music-metadata';

(async () => {
  const fileInput = document.querySelector('input[type="file"]');
  const file = fileInput.files[0];
  
  try {
    const metadata = await parseBlob(file);
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseBuffer function

Parses metadata from an audio file where the audio data is held in a Uint8Array or Buffer. This function is particularly useful when you already have audio data in memory.

Syntax
parseBuffer(uint8Array: Uint8Array, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • uint8Array: Uint8Array

    A Uint8Array containing the audio data to be parsed.

  • fileInfo: IFileInfo | string (optional)

    An object containing file information such as mimeType and size. Alternatively, you can pass a MIME-type string directly. This helps the parser understand the format of the audio data.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio file.

Example
import { parseBuffer } from 'music-metadata';
import fs from 'fs';

(async () => {
  const buffer = fs.readFileSync('path/to/audio/file.mp3');

  try {
    const metadata = await parseBuffer(buffer, { mimeType: 'audio/mpeg' });
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseFromTokenizer function

Parses metadata from an audio source that implements the strtok3 ITokenizer interface. This is a low-level function that provides flexibility for advanced use cases, such as parsing metadata from streaming audio or custom data sources.

This also enables special read modules like:

Syntax
parseFromTokenizer(tokenizer: ITokenizer, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • tokenizer: ITokenizer

    An instance of an ITokenizer that provides access to the audio data. The tokenizer abstracts the reading process, enabling support for various types of sources, including streams, buffers, or custom data readers.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio source, including information like the title, artist, album, and more.

Example
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { S3Client } from '@aws-sdk/client-s3';
import { makeTokenizer } from '@tokenizer/s3';
import { parseFromTokenizer as mmParseFromTokenizer } from 'music-metadata';

// Configure the S3 client
const s3 = new S3Client({
  region: 'eu-west-2',
  credentials: fromNodeProviderChain(),
});

// Helper function to create a tokenizer for S3 objects
async function makeS3TestDataTokenizer(key, options) {
  return await makeTokenizer(s3, {
    Bucket: 'music-metadata',
    Key: key,
  }, options);
}

// Function to read and log metadata from an S3 object
async function readMetadata() {
  try {
    // Create a tokenizer for the specified S3 object
    const tokenizer = await makeS3TestDataTokenizer('path/to/audio/file.mp3', { disableChunked: false });

    // Parse the metadata from the tokenizer
    const metadata = await mmParseFromTokenizer(tokenizer);

    // Log the retrieved metadata
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
}

// Execute the metadata reading function
readMetadata();
Additional Resources
  • strtok3 - Learn more about the ITokenizer interface and how to implement it for various use cases.
  • AWS SDK for JavaScript - Documentation on using the AWS SDK to interact with S3 and other AWS services.
  • @tokenizer/s3 - Example of ITokenizer implementation.

Handling Parse Errors

music-metadata exports custom error classes that extend JavaScript Error. Parsing can also reject with other errors, such as filesystem, stream, or tokenizer errors. Handle caught values as unknown in TypeScript and narrow them before accessing error properties.

Union of Parse Errors

The UnionOfParseErrors type groups the following library error classes; it does not describe every possible rejection:

export type UnionOfParseErrors =
  | CouldNotDetermineFileTypeError
  | UnsupportedFileTypeError
  | UnexpectedFileContentError
  | FieldDecodingError
  | InternalParserError;

Error Types

  • CouldNotDetermineFileTypeError: Raised when the file type cannot be determined.
  • UnsupportedFileTypeError: Raised when an unsupported file type is encountered.
  • UnexpectedFileContentError: Raised when the file content does not match the expected format.
  • FieldDecodingError: Raised when a specific field in the file cannot be decoded.
  • InternalParserError: Raised for internal parser errors.

Other functions

orderTags function

Converts an array of native tags to a dictionary keyed by tag identifier. Each value is an array of tag values.

orderTags(nativeTags: ITag[]): INativeTagDict
import { parseFile, orderTags } from 'music-metadata';
import { inspect } from 'util';

(async () => {
  try {
    const metadata = await parseFile('../test/samples/MusicBrainz - Beth Hart - Sinner\'s Prayer [id3v2.3].V2.mp3');
    const orderedTags = orderTags(metadata.native['ID3v2.3']);
    console.log(inspect(orderedTags, { showHidden: false, depth: null }));
  } catch (error) {
    console.error(error.message);
  }
})();

ratingToStars function

Can be used to convert the normalized rating value to the 0..5 stars, where 0 an undefined rating, 1 the star the lowest rating and 5 the highest rating.

ratingToStars(rating: number | undefined): number

selectCover function

Select cover image based on image type field, otherwise the first picture in file.

export function selectCover(pictures?: IPicture[]): IPicture | null
import { parseFile, selectCover } from 'music-metadata';

(async () => {
  const {common} = await parseFile(filePath);
  const cover = selectCover(common.picture); // pick the cover image
}
)();

getSupportedMimeTypes function

Returns a list of supported MIME-types. This may include some MIME-types which are not formally recognized.

IOptions Interface

  • duration: boolean (default: false)

    When true, the parser will read the entire media file if necessary to determine the duration. This is only applicable in cases where duration cannot be reliably inferred without full file analysis. Note that enabling this option does not guarantee that duration will be available, only that the parser will attempt to calculate it when possible, even if it requires reading the full file.

  • includeChapters: boolean (default: false) When true, the MP4 parser reads QuickTime chapter tracks and Nero chpl chapter lists. A usable QuickTime chapter track takes precedence over a Nero list. Files, buffers, and Blobs support chapters whether moov appears before or after mdat. For forward-only streams, moov must appear before the chapter data.

  • maxMemoryAllocation: number (default: 67108864, 64 MiB)

    Maximum bytes buffered for a single metadata payload, accumulated Ogg packet, or tokenizer stream lookahead. Must be a positive safe integer. Parsing rejects payloads above this limit before allocating them. The parser configures this limit once on its strtok3 tokenizers, including tokenizers for embedded tags. Oversized tokenizer allocations or stream lookahead reject with strtok3.BufferSizeError. When using parseFromTokenizer(), also configure maxBufferSize on the supplied tokenizer at creation. Increase it for files with unusually large metadata or cover art, or lower it for constrained environments. Audio/video data that is skipped does not count toward this limit. This does not cap total process memory: decoded metadata, multiple retained tags, and temporary copies can require additional memory.

  • mkvUseIndex: boolean (default: false)

    When true, the parser uses the SeekHead index in Matroska (MKV) files to skip segment and cluster elements. This experimental feature can improve performance, but:

    • Metadata not listed in the SeekHead may be skipped.
    • If the SeekHead is missing, this option has no effect.
  • observer: (update: IMetadataEvent) => void:

    Callback function triggered when common tags or format properties are updated during parsing. Allows real-time monitoring of metadata as it becomes available.

  • skipCovers: boolean (default: false)

    When true, embedded cover art (images) will not be extracted. Useful for reducing memory and processing when cover images are unnecessary.

  • skipPostHeaders: boolean (default: false) When true, tag headers located at the end of the file will not be read. This is particularly beneficial for streaming input, as it avoids the need to read the entire stream.

[!NOTE]

  • format.duration may be available without enabling duration. Set duration: true to allow additional scanning when needed; duration can still be unavailable.
  • Using mkvUseIndex can improve performance in Matroska files, but be aware of potential side effects, such as missing metadata due to skipped elements.

IAudioMetadata interface

If the returned promise resolves, the metadata (TypeScript IAudioMetadata interface) contains:

  • metadata.format Audio format information
  • metadata.common Is a generic (abstract) way of reading metadata information.
  • metadata.format.trackInfo Describes individual audio and video tracks when available.
  • metadata.native Maps each tag format to an array of native (original) tags found in the parsed audio file.
  • metadata.quality.warnings Contains non-fatal parsing warnings, each with a message string.

metadata.format

The questionmark ? indicates the property is optional.

Audio format information. Defined in the TypeScript IFormat interface:

  • format.container?: string Audio encoding format. e.g.: 'flac'
  • format.codec? Name of the codec (algorithm used for the audio compression)
  • format.codecProfile?: string Codec profile / settings
  • format.tagTypes?: TagType[] List of tagging formats found in parsed audio file
  • format.duration?: number Duration in seconds (existing audio/container summary; complete presentation duration for video-only files)
  • format.bitrate?: number Existing audio/container summary bitrate in bits per second
  • format.containerDuration?: number Complete media presentation duration in seconds, including video
  • format.overallBitrate?: number Average bitrate of the entire file in bits per second, including container overhead; requires a known file size and presentation duration
  • format.sampleRate?: number Sampling rate in Samples per second (S/s)
  • format.bitsPerSample?: number Audio bit depth
  • format.lossless?: boolean True if lossless, false for lossy encoding
  • format.numberOfChannels?: number Number of audio channels
  • format.creationTime?: Date Track creation time
  • format.modificationTime?: Date Track modification / tag update time
  • format.trackGain?: number Track gain in dB
  • format.albumGain?: number Album gain in dB

metadata.format.trackInfo

metadata.format.trackInfo provides the same track abstraction for single-stream audio files and multi-track containers (MPEG-4, Matroska, ASF, and Ogg). Tracks can carry audio, video, subtitles, or metadata. Import TrackType from music-metadata to select tracks without knowing the container:

import { parseFile, TrackType } from 'music-metadata';

const { format } = await parseFile('movie.mp4', { duration: true });
const audioTracks = format.trackInfo.filter(track => track.type === TrackType.audio);
const videoTracks = format.trackInfo.filter(track => track.type === TrackType.video);
for (const track of videoTracks) {
  console.log(track.duration, track.bitrate, track.video?.pixelWidth, track.video?.pixelHeight);
  console.log(track.video?.frameRate);
}
console.log(format.containerDuration, format.overallBitrate);

Each entry describes one discovered track. The order follows container discovery and does not identify a preferred track; use type, container flags, and language to choose one. In MPEG-4, the codec and media properties describe the first sample description, even when the track has multiple sample descriptions. In Ogg, entries describe logical media streams; Skeleton headers do not create media tracks. Single-stream audio parsers map their format properties to one audio track after parsing.

Properties are optional when unavailable and are not copied between tracks. In particular, a container or summary bitrate is not a per-track bitrate. The existing format.duration and format.bitrate fields retain their summary semantics. Use containerDuration for the complete presentation and overallBitrate for the actual file size multiplied by eight and divided by that duration. These statistics remain unset when timing is unavailable; overallBitrate also requires a known input size.

MPEG-4 derives audio and video timing from media headers, sample tables, and fragments, including fragment defaults and decode timestamps. Track bitrates use sample sizes and duration; video properties include encoded dimensions, display dimensions, and average frame rate. ASF supplies stream dimensions, stream bitrates, and extended stream timing and frame rate when present. Standalone and nested Stream Properties Objects describe actual streams; Codec List entries supply names without creating unused tracks.

Matroska applies specified defaults for flags, language, channels, and sample rate, and prefers IETF language tags when present. Track statistics tags provide duration, bitrate, and frame count; without these tags, per-track timing may be unavailable even when segment duration is known. Media clusters are not scanned to calculate missing track statistics.

Ogg/Theora duration comes from granule positions. Set duration: true to allow scanning beyond the initial metadata pages. Once a video stream has been fully read, its average bitrate uses that logical stream's payload bytes, including codec headers and excluding Ogg framing and other streams. Resolution and frame rate are available from the identification header. Audio streams retain their own codec bitrate semantics.

For Ogg/Opus, the per-track average bitrate uses the logical stream's payload bytes, including codec headers and excluding Ogg framing and other streams. It requires the logical stream's end-of-stream (EOS) page and a known duration; reaching input EOF alone is insufficient. Set duration: true to allow scanning when needed. The summary format.bitrate retains its existing file-size estimate and can differ from the per-track bitrate. Vorbis and Speex use nominal bitrates when their headers provide them.

metadata.format.trackInfo is an array of trackInfo objects, empty when no track information is available.

trackInfo

Individual track information. Defined in the TypeScript ITrackInfo interface:

  • trackInfo.id?: number Container track ID/number, or Ogg stream serial number; only meaningful within the file
  • trackInfo.type?: TrackType Track type (audio, video, subtitle, metadata, or other known types)
  • trackInfo.codecId?: string Container-specific codec identifier, such as mp4a, A_AAC, or ASF audio format tag 0x0161
  • trackInfo.codecName?: string Codec name
  • trackInfo.codecProfile?: string Codec profile
  • trackInfo.duration?: number Track duration in seconds
  • trackInfo.bitrate?: number Encoded track bitrate in bits per second
  • trackInfo.lossless?: boolean Whether the track uses lossless compression
  • trackInfo.codecSettings?: string Codec settings
  • trackInfo.flagEnabled?: boolean Whether the track is enabled; Matroska defaults to true, MPEG-4 uses the track header flag
  • trackInfo.flagDefault?: boolean Whether the container marks the track as a default selection; Matroska defaults to true
  • trackInfo.flagForced?: boolean Whether a subtitle track should be displayed without explicit selection
  • trackInfo.flagLacing?: boolean Whether a Matroska track may contain blocks using lacing; defaults to true
  • trackInfo.name?: string A human-readable track name.
  • trackInfo.language?: string Specifies the language of the track
  • trackInfo.audio?: IAudioTrack, see trackInfo.audio
  • trackInfo.video?: IVideoTrack, see trackInfo.video
trackInfo.audio
  • trackInfo.audio.numberOfSamples?: number Number of decoded sample frames (one sample per channel), when known
  • trackInfo.audio.samplingFrequency?: number Sample rate in hertz; for Opus, the informational original input rate
  • trackInfo.audio.outputSamplingFrequency?: number Output sample rate in hertz; Opus granules and sample counts use 48000 Hz
  • trackInfo.audio.channels?: number
  • trackInfo.audio.channelPositions?: Uint8Array
  • trackInfo.audio.bitDepth?: number
trackInfo.video
  • trackInfo.video.frameRate?: number Frames per second, when known
  • trackInfo.video.flagInterlaced?: boolean
  • trackInfo.video.stereoMode?: number
  • trackInfo.video.pixelWidth?: number
  • trackInfo.video.pixelHeight?: number
  • trackInfo.video.displayWidth?: number
  • trackInfo.video.displayHeight?: number
  • trackInfo.video.displayUnit?: number
  • trackInfo.video.aspectRatioType?: number
  • trackInfo.video.colourSpace?: Uint8Array
  • trackInfo.video.gammaValue?: number

metadata.common

Common tag documentation is automatically generated.

Examples

In order to read the duration of a stream (with the exception of file streams), in some cases you should pass the size of the file in bytes.

import { parseStream } from 'music-metadata';
import { inspect } from 'util';

(async () => {
    const metadata = await parseStream(someReadStream, {mimeType: 'audio/mpeg', size: 26838}, {duration: true});
    console.log(inspect(metadata, {showHidden: false, depth: null}));
    someReadStream.close();
  }
)();

Access cover art

Via metadata.common.picture you can access an array of cover art if present. Each picture has this interface:

/**
 * Attached picture, typically used for cover art
 */
export interface IPicture {
  /**
   * Image mime type
   */
  format: string;
  /**
   * Image data
   */
  data: Uint8Array;
  /**
   * Optional description
   */
  description?: string;
  /**
   * Picture type
   */
  type?: string;
}

To assign img HTML-object you can do something like:

import {uint8ArrayToBase64} from 'uint8array-extras';

img.src = `data:${picture.format};base64,${uint8ArrayToBase64(picture.data)}`;

Dependencies

Dependency diagram:

graph TD;
    MMN("music-metadata (Node.js entry point)")-->MMP
    MMN-->FTN
    MMP("music-metadata (primary entry point)")-->S(strtok3)
    MMP-->TY(token-types)
    MMP-->FTP
    MMP-->UAE
    FTN("file-type (Node.js entry point)")-->FTP
    FTP("file-type (primary entry point)")-->S
    S(strtok3)-->TO("@tokenizer/token")
    TY(token-types)-->TO
    TY-->IE("ieee754")
    FTP-->TY
    NS("node:stream")
    FTN-->NS
    FTP-->UAE(uint8array-extras)
    style NS fill:#F88,stroke:#A44
    style IE fill:#CCC,stroke:#888
    style FTN fill:#FAA,stroke:#A44
    style MMN fill:#FAA,stroke:#A44

Dependency list:

CommonJS backward compatibility

Using Node.js ≥ 22, which is support loading ESM module via require

const mm = require('music-metadata');

Alternatively, dynamically import music-metadata:

(async () => {
  // Dynamically loads the ESM module in a CommonJS project
  const mm = await import('music-metadata');
})();

For CommonJS TypeScript projects, I recommend to avoid using commonjs for the TypeScript compiler module option, and either use node16 or nodenext, which enable utilizing dynamic import.

If you do want to use the classic commonjs option, this is how you can get the dynamic import to work.

import {loadEsm} from 'load-esm';

(async () => {
  // Dynamically loads the ESM module in a CommonJS project
  const mm = await loadEsm<typeof import('music-metadata')>('music-metadata');
})();

When you use Node.js version ≥ 22, which supports loading ESM modules via require, this compensates for that issue.

Frequently Asked Questions

How can I traverse (a long) list of files?

What is important that file parsing should be done in a sequential manner. In a plain loop, due to the asynchronous character (like most JavaScript functions), it would cause all the files to run in parallel which is will cause your application to hang in no time. There are multiple ways of achieving this:

  1. Using recursion

    import { parseFile } from 'music-metadata';
    
    function parseFiles(audioFiles) {
    
      const audioFile = audioFiles.shift();
    
      if (audioFile) {
        return parseFile(audioFile).then(metadata => {
          // Do great things with the metadata
          return parseFiles(audioFiles); // process rest of the files AFTER we are finished
        })
      }
    }
    
    
  2. Use async/await

    Use async/await

    import { parseFile } from 'music-metadata';
    
    // it is required to declare the function 'async' to allow the use of await
    async function parseFiles(audioFiles) {
    
        for (const audioFile of audioFiles) {
    
            // await will ensure the metadata parsing is completed before we move on to the next file
            const metadata = await parseFile(audioFile);
            // Do great things with the metadata
        }
    }
    

Using music-metadata with TypeScript and module-resolution set to bundler.

If the TypeScript compiler option moduleResolution is set to "bundler", it does not set the ECMAScript "node" condition, causing the Node specific function fail to import.

This is the case using Next.js. See issue #2370 how to resolve that.

Licence

This project is licensed under the MIT License. Feel free to use, modify, and distribute as needed.

aiff
ape
asf
audio
dsd
flac
id3
m4a
metadata
mp3
mp4
musepack
musicbrainz
ogg
opus
picard
tag
tags
vorbis
wav

Project health

Overall

3.8/10

Maintained

10/10

Code review

0/10
OpenSSF Scorecard

Latest release

12.2.0 · Oct 12, 2026

Releases this year

23

Significant stargazers

Espen Hovlandsdal

672 followers · starred Sep 2019

Jakub T. Jankiewicz

615 followers · starred Dec 2024

Jordan Eldredge

988 followers · starred Jul 2018

Myriad-Dreamin

958 followers · starred Mar 2020

Borewit/music-metadata

Metadata parser for audio and video media files. Supports file and stream inputs in Node.js and browser environments, extracting format, tag, and duration information.

TypeScript

1,330

3,733 commits

updated Oct 12, 2026

See the code

README

CI NPM version npm downloads codecov Codacy Badge CodeQL DeepScan grade Known Vulnerabilities

music-metadata

logo

Key features:

  • Comprehensive Format Support: Supports popular audio formats like MP3, MP4, FLAC, Ogg, WAV, AIFF, and more.
  • Extensive Metadata Extraction: Extracts detailed metadata, including ID3v1, ID3v2, APE, Vorbis, and iTunes/MP4 tags.
  • Streaming Support: Efficiently handles large audio files by reading metadata from streams, making it suitable for server-side and browser-based applications.
  • Promise-Based API: Provides a modern, promise-based API for easy integration into asynchronous workflows.
  • Cross-Platform: Works in both Node.js and browser environments with the help of bundlers like Webpack or Rollup.

The music-metadata module is ideal for developers working on media applications, music players, or any project that requires access to detailed audio file metadata.

Compatibility

Module: version 8 migrated from CommonJS to pure ECMAScript Module (ESM). The distributed JavaScript codebase targets ECMAScript 2023 (14th Edition).

[!NOTE] See also CommonJS backward Compatibility

This module requires a Node.js ≥ 22 engine. It can also be used in a browser environment when bundled with a module bundler.

Support the Project

If you find this project useful and would like to support its development, consider sponsoring or contributing:

Features

Support for audio file types

Audio formatDescriptionLogo
AIFF / AIFF-CAudio Interchange File FormatApple rainbow logo
AACADTS / Advanced Audio CodingAAC logo
APEMonkey's AudioMonkey's Audio logo
ASFAdvanced Systems Format
BWFExtended WAV format for broadcast and archiving
CAFCore Audio File FormatApple rainbow logo
DSDIFFPhilips DSDIFFDSD logo
DSFSony's DSD Stream FileDSD logo
FLACFree Lossless Audio CodecFLAC logo
MP2MPEG-1 Audio Layer II (predecessor to MP3)
MatroskaMatroska (EBML), mka, mkvMatroska logo
MP3MPEG-1 / MPEG-2 Audio Layer IIIMP3 logo
MPCMusepack SV7musepack logo
MPEG 4mp4, m4a, m4vmpeg 4 logo
OggOpen container formatOgg logo
OpusLow-latency, high-quality codec for speech and musicOpus logo
SpeexOpen-source speech codec optimized for VoIPSpeex logo
TheoraOpen video compression format (typically paired with Ogg)Theora logo
VorbisVorbis audio compressionVorbis logo
WAVUncompressed PCM audio in RIFF container
WebMWebMMatroska logo
WVWavPackWavPack logo
WMAWindows Media AudioWindows Media logo

Supported tag headers

Following tag header formats are supported:

Following lyric formats are supported:

  • LRC
  • Synchronized lyrics (SYLT)
  • Unsynchronized lyrics (USLT)

Support for MusicBrainz tags as written by Picard. ReplayGain tags are supported.

Audio format & encoding details

Support for encoding / format details:

Online demo's

Used by around 50k+ GitHub projects.

Usage

Installation

Install using npm:

npm install music-metadata

or using yarn:

yarn add music-metadata

API Documentation

Overview

Node.js specific functions to read an audio file or stream:

  1. File Parsing: Parse audio files directly from the filesystem using the parseFile function
  2. Stream Parsing: Parse audio metadata from a Node.js Readable stream using the parseStream function.

Cross-platform functions available to read an audio file or stream:

There are multiple ways to parse (read) audio tracks:

  1. Web Stream Parsing: Parse audio data from a web-compatible ReadableStream using the parseWebStream function.
  2. Blob Parsing: Parse audio metadata from a (Web API) Blob or File using the parseBlob function.
  3. Buffer Parsing: Parse audio metadata from a Uint8Array or Buffer using the parseBuffer function.
  4. Tokenizer Parsing: Use a custom or third-party strtok3 ITokenizer to parse using the parseFromTokenizer function.

[!NOTE] Direct file access in Node.js is generally faster because it can 'jump' to various parts of the file without reading intermediate data.

Node.js specific functions

These functions use Node.js-specific APIs, making them incompatible with browser-based JavaScript engines.

parseFile function

The parseFile function is intended for extracting metadata from audio files on the local filesystem in a Node.js environment. It reads the specified file, parses its audio metadata, and returns a promise that resolves with this information.

Syntax
parseFile(filePath: string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • filePath: string

    The path to the media file from which metadata should be extracted. This should be a valid path to an audio file on the local filesystem.

  • options: IOptions (optional)

    An optional configuration object that allows customization of the parsing process. These options can include whether to calculate the file's duration, skip embedded cover art, or other parsing behaviors.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing metadata about the audio file. The metadata includes details such as the file format, codec, duration, bit rate, and any embedded tags like album, artist, or track information.

Usage Notes
  • This function is Node.js-only and relies on Node.js-specific APIs to access the filesystem.

  • For browser environments, consider using the parseBlob to parse File object objects.

Example:

The following example demonstrates how to use the parseFile function to read metadata from an audio file:

import { parseFile } from 'music-metadata';
import { inspect } from 'node:util';

(async () => {
  try {
    const filePath = 'test/samples/MusicBrainz - Beth Hart - Sinner\'s Prayer [id3v2.3].V2.mp3';
    const metadata = await parseFile(filePath);

    // Output the parsed metadata to the console in a readable format
    console.log(inspect(metadata, { showHidden: false, depth: null }));
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseStream function

The parseStream function is used to parse metadata from an audio track provided as a Node.js Readable stream. This is particularly useful for processing audio data that is being streamed or piped from another source, such as a web server or file system.

Syntax:
parseStream(stream: Readable, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters:
  • stream: Readable:

    The Node.js Readable stream from which the audio data is read. This stream should provide the raw audio data to be analyzed.

  • fileInfo: IFileInfo (optional)

    An object containing file-related information or a string representing the MIME-type of the audio stream. The fileInfo parameter can help the parser to correctly identify the audio format and may include:

    • mimeType: A string representing the MIME-type (e.g., audio/mpeg).

      If provided, it is assumed the streamed file content is to be the MIME-type. If not provided, the parser will attempt to determine the format based on the content of the stream.

    • size: The total size of the audio stream in bytes (useful for streams with a known length).

    • path: A string representing the file path or filename, which can also assist in determining the format.

  • options: IOptions (optional)

    An optional object containing additional parsing options. These options allow you to customize the parsing process, such as whether to calculate the duration or skip cover art extraction.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing detailed metadata about the audio stream. This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.

Usage Notes
  • This function is only available in Node.js environments, as it relies on the Node.js stream API.
Example:

The following example demonstrates how to use the parseStream function to read metadata from an audio stream:

import { parseStream } from 'music-metadata';
import { createReadStream } from 'fs';

(async () => {
  try {
    // Create a readable stream from a file
    const audioStream = createReadStream('path/to/audio/file.mp3');

    // Parse the metadata from the stream
    const metadata = await parseStream(audioStream, { mimeType: 'audio/mpeg'});

    // Log the parsed metadata
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

Cross-platform functions

These functions are designed to be cross-platform, meaning they can be used in both Node.js and web browsers.

parseWebStream function

The parseWebStream function is used to extract metadata from an audio track provided as a web-compatible ReadableStream. This function is ideal for applications running in web environments, such as browsers, where audio data is streamed over the network or read from other web-based sources.

Syntax
parseWebStream(webStream: ReadableStream<Uint8Array>, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • webStream: ReadableStream<Uint8Array>

    A ReadableStream that provides the audio data to be parsed. This stream should emit Uint8Array chunks, representing the raw audio data.

  • fileInfo: IFileInfo (optional)

    An object containing file-related information or a string representing the MIME-type of the audio stream. The fileInfo parameter can help the parser to correctly identify the audio format and may include:

    • mimeType: A string representing the MIME-type (e.g., audio/mpeg).

      If provided, it is assumed the streamed file content is to be the MIME-type. If not provided, the parser will attempt to determine the format based on the content of the stream.

    • size: The total size of the audio stream in bytes (useful for streams with a known length).

    • path: A string representing the file path or filename, which can also assist in determining the format.

  • options: IOptions (optional)

    An optional object containing additional parsing options. These options allow you to customize the parsing process, such as whether to calculate the duration or skip cover art extraction.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to an IAudioMetadata object containing detailed metadata about the audio stream. This metadata includes information about the format, codec, duration, bitrate, and any embedded tags such as artist, album, or track information.

Example

Here’s an example of how to use the parseWebStream function to extract metadata from an audio stream in a web application:

import { parseWebStream } from 'music-metadata';

(async () => {
  try {
    // Fetch the audio file
    const response = await fetch('https://github.com/Borewit/test-audio/raw/refs/heads/master/Various%20Artists%20-%202008%20-%20netBloc%20Vol%2013%20-%20Color%20in%20a%20World%20of%20Monochrome%20%5BAAC-40%5D/1.02.%20Solid%20Ground.m4a');

    // Extract the Content-Length header and convert it to a number
    const contentLength = response.headers.get('Content-Length');
    const size = contentLength ? parseInt(contentLength, 10) : undefined;

    // Parse the metadata from the web stream
    const metadata = await parseWebStream(response.body, {
      mimeType: response.headers.get('Content-Type'),
      size // Important to pass the content-length
    });

    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

The example uses the fetch API to retrieve an audio file from a URL. The response.body provides a ReadableStream that is then passed to parseWebStream.

parseBlob function

Parses metadata from an audio file represented as a Blob. This function reads slices of the Blob and supports both browser File objects and Node.js Blob objects.

Syntax
parseBlob(blob: Blob, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • blob: Blob

    The Blob object containing the audio data to be parsed. This can be a File selected by the user or a Blob containing audio data. The Blob size and MIME type are passed to the parser.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio file.

Example
import { parseBlob } from 'music-metadata';

(async () => {
  const fileInput = document.querySelector('input[type="file"]');
  const file = fileInput.files[0];
  
  try {
    const metadata = await parseBlob(file);
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseBuffer function

Parses metadata from an audio file where the audio data is held in a Uint8Array or Buffer. This function is particularly useful when you already have audio data in memory.

Syntax
parseBuffer(uint8Array: Uint8Array, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • uint8Array: Uint8Array

    A Uint8Array containing the audio data to be parsed.

  • fileInfo: IFileInfo | string (optional)

    An object containing file information such as mimeType and size. Alternatively, you can pass a MIME-type string directly. This helps the parser understand the format of the audio data.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio file.

Example
import { parseBuffer } from 'music-metadata';
import fs from 'fs';

(async () => {
  const buffer = fs.readFileSync('path/to/audio/file.mp3');

  try {
    const metadata = await parseBuffer(buffer, { mimeType: 'audio/mpeg' });
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
})();

parseFromTokenizer function

Parses metadata from an audio source that implements the strtok3 ITokenizer interface. This is a low-level function that provides flexibility for advanced use cases, such as parsing metadata from streaming audio or custom data sources.

This also enables special read modules like:

Syntax
parseFromTokenizer(tokenizer: ITokenizer, options?: IOptions): Promise<IAudioMetadata>
Parameters
  • tokenizer: ITokenizer

    An instance of an ITokenizer that provides access to the audio data. The tokenizer abstracts the reading process, enabling support for various types of sources, including streams, buffers, or custom data readers.

  • options: IOptions (optional)

    An optional configuration object that specifies parsing options.

Returns
  • Promise<IAudioMetadata>:

    A promise that resolves to the metadata of the audio source, including information like the title, artist, album, and more.

Example
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { S3Client } from '@aws-sdk/client-s3';
import { makeTokenizer } from '@tokenizer/s3';
import { parseFromTokenizer as mmParseFromTokenizer } from 'music-metadata';

// Configure the S3 client
const s3 = new S3Client({
  region: 'eu-west-2',
  credentials: fromNodeProviderChain(),
});

// Helper function to create a tokenizer for S3 objects
async function makeS3TestDataTokenizer(key, options) {
  return await makeTokenizer(s3, {
    Bucket: 'music-metadata',
    Key: key,
  }, options);
}

// Function to read and log metadata from an S3 object
async function readMetadata() {
  try {
    // Create a tokenizer for the specified S3 object
    const tokenizer = await makeS3TestDataTokenizer('path/to/audio/file.mp3', { disableChunked: false });

    // Parse the metadata from the tokenizer
    const metadata = await mmParseFromTokenizer(tokenizer);

    // Log the retrieved metadata
    console.log(metadata);
  } catch (error) {
    console.error('Error parsing metadata:', error.message);
  }
}

// Execute the metadata reading function
readMetadata();
Additional Resources
  • strtok3 - Learn more about the ITokenizer interface and how to implement it for various use cases.
  • AWS SDK for JavaScript - Documentation on using the AWS SDK to interact with S3 and other AWS services.
  • @tokenizer/s3 - Example of ITokenizer implementation.

Handling Parse Errors

music-metadata exports custom error classes that extend JavaScript Error. Parsing can also reject with other errors, such as filesystem, stream, or tokenizer errors. Handle caught values as unknown in TypeScript and narrow them before accessing error properties.

Union of Parse Errors

The UnionOfParseErrors type groups the following library error classes; it does not describe every possible rejection:

export type UnionOfParseErrors =
  | CouldNotDetermineFileTypeError
  | UnsupportedFileTypeError
  | UnexpectedFileContentError
  | FieldDecodingError
  | InternalParserError;

Error Types

  • CouldNotDetermineFileTypeError: Raised when the file type cannot be determined.
  • UnsupportedFileTypeError: Raised when an unsupported file type is encountered.
  • UnexpectedFileContentError: Raised when the file content does not match the expected format.
  • FieldDecodingError: Raised when a specific field in the file cannot be decoded.
  • InternalParserError: Raised for internal parser errors.

Other functions

orderTags function

Converts an array of native tags to a dictionary keyed by tag identifier. Each value is an array of tag values.

orderTags(nativeTags: ITag[]): INativeTagDict
import { parseFile, orderTags } from 'music-metadata';
import { inspect } from 'util';

(async () => {
  try {
    const metadata = await parseFile('../test/samples/MusicBrainz - Beth Hart - Sinner\'s Prayer [id3v2.3].V2.mp3');
    const orderedTags = orderTags(metadata.native['ID3v2.3']);
    console.log(inspect(orderedTags, { showHidden: false, depth: null }));
  } catch (error) {
    console.error(error.message);
  }
})();

ratingToStars function

Can be used to convert the normalized rating value to the 0..5 stars, where 0 an undefined rating, 1 the star the lowest rating and 5 the highest rating.

ratingToStars(rating: number | undefined): number

selectCover function

Select cover image based on image type field, otherwise the first picture in file.

export function selectCover(pictures?: IPicture[]): IPicture | null
import { parseFile, selectCover } from 'music-metadata';

(async () => {
  const {common} = await parseFile(filePath);
  const cover = selectCover(common.picture); // pick the cover image
}
)();

getSupportedMimeTypes function

Returns a list of supported MIME-types. This may include some MIME-types which are not formally recognized.

IOptions Interface

  • duration: boolean (default: false)

    When true, the parser will read the entire media file if necessary to determine the duration. This is only applicable in cases where duration cannot be reliably inferred without full file analysis. Note that enabling this option does not guarantee that duration will be available, only that the parser will attempt to calculate it when possible, even if it requires reading the full file.

  • includeChapters: boolean (default: false) When true, the MP4 parser reads QuickTime chapter tracks and Nero chpl chapter lists. A usable QuickTime chapter track takes precedence over a Nero list. Files, buffers, and Blobs support chapters whether moov appears before or after mdat. For forward-only streams, moov must appear before the chapter data.

  • maxMemoryAllocation: number (default: 67108864, 64 MiB)

    Maximum bytes buffered for a single metadata payload, accumulated Ogg packet, or tokenizer stream lookahead. Must be a positive safe integer. Parsing rejects payloads above this limit before allocating them. The parser configures this limit once on its strtok3 tokenizers, including tokenizers for embedded tags. Oversized tokenizer allocations or stream lookahead reject with strtok3.BufferSizeError. When using parseFromTokenizer(), also configure maxBufferSize on the supplied tokenizer at creation. Increase it for files with unusually large metadata or cover art, or lower it for constrained environments. Audio/video data that is skipped does not count toward this limit. This does not cap total process memory: decoded metadata, multiple retained tags, and temporary copies can require additional memory.

  • mkvUseIndex: boolean (default: false)

    When true, the parser uses the SeekHead index in Matroska (MKV) files to skip segment and cluster elements. This experimental feature can improve performance, but:

    • Metadata not listed in the SeekHead may be skipped.
    • If the SeekHead is missing, this option has no effect.
  • observer: (update: IMetadataEvent) => void:

    Callback function triggered when common tags or format properties are updated during parsing. Allows real-time monitoring of metadata as it becomes available.

  • skipCovers: boolean (default: false)

    When true, embedded cover art (images) will not be extracted. Useful for reducing memory and processing when cover images are unnecessary.

  • skipPostHeaders: boolean (default: false) When true, tag headers located at the end of the file will not be read. This is particularly beneficial for streaming input, as it avoids the need to read the entire stream.

[!NOTE]

  • format.duration may be available without enabling duration. Set duration: true to allow additional scanning when needed; duration can still be unavailable.
  • Using mkvUseIndex can improve performance in Matroska files, but be aware of potential side effects, such as missing metadata due to skipped elements.

IAudioMetadata interface

If the returned promise resolves, the metadata (TypeScript IAudioMetadata interface) contains:

  • metadata.format Audio format information
  • metadata.common Is a generic (abstract) way of reading metadata information.
  • metadata.format.trackInfo Describes individual audio and video tracks when available.
  • metadata.native Maps each tag format to an array of native (original) tags found in the parsed audio file.
  • metadata.quality.warnings Contains non-fatal parsing warnings, each with a message string.

metadata.format

The questionmark ? indicates the property is optional.

Audio format information. Defined in the TypeScript IFormat interface:

  • format.container?: string Audio encoding format. e.g.: 'flac'
  • format.codec? Name of the codec (algorithm used for the audio compression)
  • format.codecProfile?: string Codec profile / settings
  • format.tagTypes?: TagType[] List of tagging formats found in parsed audio file
  • format.duration?: number Duration in seconds (existing audio/container summary; complete presentation duration for video-only files)
  • format.bitrate?: number Existing audio/container summary bitrate in bits per second
  • format.containerDuration?: number Complete media presentation duration in seconds, including video
  • format.overallBitrate?: number Average bitrate of the entire file in bits per second, including container overhead; requires a known file size and presentation duration
  • format.sampleRate?: number Sampling rate in Samples per second (S/s)
  • format.bitsPerSample?: number Audio bit depth
  • format.lossless?: boolean True if lossless, false for lossy encoding
  • format.numberOfChannels?: number Number of audio channels
  • format.creationTime?: Date Track creation time
  • format.modificationTime?: Date Track modification / tag update time
  • format.trackGain?: number Track gain in dB
  • format.albumGain?: number Album gain in dB

metadata.format.trackInfo

metadata.format.trackInfo provides the same track abstraction for single-stream audio files and multi-track containers (MPEG-4, Matroska, ASF, and Ogg). Tracks can carry audio, video, subtitles, or metadata. Import TrackType from music-metadata to select tracks without knowing the container:

import { parseFile, TrackType } from 'music-metadata';

const { format } = await parseFile('movie.mp4', { duration: true });
const audioTracks = format.trackInfo.filter(track => track.type === TrackType.audio);
const videoTracks = format.trackInfo.filter(track => track.type === TrackType.video);
for (const track of videoTracks) {
  console.log(track.duration, track.bitrate, track.video?.pixelWidth, track.video?.pixelHeight);
  console.log(track.video?.frameRate);
}
console.log(format.containerDuration, format.overallBitrate);

Each entry describes one discovered track. The order follows container discovery and does not identify a preferred track; use type, container flags, and language to choose one. In MPEG-4, the codec and media properties describe the first sample description, even when the track has multiple sample descriptions. In Ogg, entries describe logical media streams; Skeleton headers do not create media tracks. Single-stream audio parsers map their format properties to one audio track after parsing.

Properties are optional when unavailable and are not copied between tracks. In particular, a container or summary bitrate is not a per-track bitrate. The existing format.duration and format.bitrate fields retain their summary semantics. Use containerDuration for the complete presentation and overallBitrate for the actual file size multiplied by eight and divided by that duration. These statistics remain unset when timing is unavailable; overallBitrate also requires a known input size.

MPEG-4 derives audio and video timing from media headers, sample tables, and fragments, including fragment defaults and decode timestamps. Track bitrates use sample sizes and duration; video properties include encoded dimensions, display dimensions, and average frame rate. ASF supplies stream dimensions, stream bitrates, and extended stream timing and frame rate when present. Standalone and nested Stream Properties Objects describe actual streams; Codec List entries supply names without creating unused tracks.

Matroska applies specified defaults for flags, language, channels, and sample rate, and prefers IETF language tags when present. Track statistics tags provide duration, bitrate, and frame count; without these tags, per-track timing may be unavailable even when segment duration is known. Media clusters are not scanned to calculate missing track statistics.

Ogg/Theora duration comes from granule positions. Set duration: true to allow scanning beyond the initial metadata pages. Once a video stream has been fully read, its average bitrate uses that logical stream's payload bytes, including codec headers and excluding Ogg framing and other streams. Resolution and frame rate are available from the identification header. Audio streams retain their own codec bitrate semantics.

For Ogg/Opus, the per-track average bitrate uses the logical stream's payload bytes, including codec headers and excluding Ogg framing and other streams. It requires the logical stream's end-of-stream (EOS) page and a known duration; reaching input EOF alone is insufficient. Set duration: true to allow scanning when needed. The summary format.bitrate retains its existing file-size estimate and can differ from the per-track bitrate. Vorbis and Speex use nominal bitrates when their headers provide them.

metadata.format.trackInfo is an array of trackInfo objects, empty when no track information is available.

trackInfo

Individual track information. Defined in the TypeScript ITrackInfo interface:

  • trackInfo.id?: number Container track ID/number, or Ogg stream serial number; only meaningful within the file
  • trackInfo.type?: TrackType Track type (audio, video, subtitle, metadata, or other known types)
  • trackInfo.codecId?: string Container-specific codec identifier, such as mp4a, A_AAC, or ASF audio format tag 0x0161
  • trackInfo.codecName?: string Codec name
  • trackInfo.codecProfile?: string Codec profile
  • trackInfo.duration?: number Track duration in seconds
  • trackInfo.bitrate?: number Encoded track bitrate in bits per second
  • trackInfo.lossless?: boolean Whether the track uses lossless compression
  • trackInfo.codecSettings?: string Codec settings
  • trackInfo.flagEnabled?: boolean Whether the track is enabled; Matroska defaults to true, MPEG-4 uses the track header flag
  • trackInfo.flagDefault?: boolean Whether the container marks the track as a default selection; Matroska defaults to true
  • trackInfo.flagForced?: boolean Whether a subtitle track should be displayed without explicit selection
  • trackInfo.flagLacing?: boolean Whether a Matroska track may contain blocks using lacing; defaults to true
  • trackInfo.name?: string A human-readable track name.
  • trackInfo.language?: string Specifies the language of the track
  • trackInfo.audio?: IAudioTrack, see trackInfo.audio
  • trackInfo.video?: IVideoTrack, see trackInfo.video
trackInfo.audio
  • trackInfo.audio.numberOfSamples?: number Number of decoded sample frames (one sample per channel), when known
  • trackInfo.audio.samplingFrequency?: number Sample rate in hertz; for Opus, the informational original input rate
  • trackInfo.audio.outputSamplingFrequency?: number Output sample rate in hertz; Opus granules and sample counts use 48000 Hz
  • trackInfo.audio.channels?: number
  • trackInfo.audio.channelPositions?: Uint8Array
  • trackInfo.audio.bitDepth?: number
trackInfo.video
  • trackInfo.video.frameRate?: number Frames per second, when known
  • trackInfo.video.flagInterlaced?: boolean
  • trackInfo.video.stereoMode?: number
  • trackInfo.video.pixelWidth?: number
  • trackInfo.video.pixelHeight?: number
  • trackInfo.video.displayWidth?: number
  • trackInfo.video.displayHeight?: number
  • trackInfo.video.displayUnit?: number
  • trackInfo.video.aspectRatioType?: number
  • trackInfo.video.colourSpace?: Uint8Array
  • trackInfo.video.gammaValue?: number

metadata.common

Common tag documentation is automatically generated.

Examples

In order to read the duration of a stream (with the exception of file streams), in some cases you should pass the size of the file in bytes.

import { parseStream } from 'music-metadata';
import { inspect } from 'util';

(async () => {
    const metadata = await parseStream(someReadStream, {mimeType: 'audio/mpeg', size: 26838}, {duration: true});
    console.log(inspect(metadata, {showHidden: false, depth: null}));
    someReadStream.close();
  }
)();

Access cover art

Via metadata.common.picture you can access an array of cover art if present. Each picture has this interface:

/**
 * Attached picture, typically used for cover art
 */
export interface IPicture {
  /**
   * Image mime type
   */
  format: string;
  /**
   * Image data
   */
  data: Uint8Array;
  /**
   * Optional description
   */
  description?: string;
  /**
   * Picture type
   */
  type?: string;
}

To assign img HTML-object you can do something like:

import {uint8ArrayToBase64} from 'uint8array-extras';

img.src = `data:${picture.format};base64,${uint8ArrayToBase64(picture.data)}`;

Dependencies

Dependency diagram:

graph TD;
    MMN("music-metadata (Node.js entry point)")-->MMP
    MMN-->FTN
    MMP("music-metadata (primary entry point)")-->S(strtok3)
    MMP-->TY(token-types)
    MMP-->FTP
    MMP-->UAE
    FTN("file-type (Node.js entry point)")-->FTP
    FTP("file-type (primary entry point)")-->S
    S(strtok3)-->TO("@tokenizer/token")
    TY(token-types)-->TO
    TY-->IE("ieee754")
    FTP-->TY
    NS("node:stream")
    FTN-->NS
    FTP-->UAE(uint8array-extras)
    style NS fill:#F88,stroke:#A44
    style IE fill:#CCC,stroke:#888
    style FTN fill:#FAA,stroke:#A44
    style MMN fill:#FAA,stroke:#A44

Dependency list:

CommonJS backward compatibility

Using Node.js ≥ 22, which is support loading ESM module via require

const mm = require('music-metadata');

Alternatively, dynamically import music-metadata:

(async () => {
  // Dynamically loads the ESM module in a CommonJS project
  const mm = await import('music-metadata');
})();

For CommonJS TypeScript projects, I recommend to avoid using commonjs for the TypeScript compiler module option, and either use node16 or nodenext, which enable utilizing dynamic import.

If you do want to use the classic commonjs option, this is how you can get the dynamic import to work.

import {loadEsm} from 'load-esm';

(async () => {
  // Dynamically loads the ESM module in a CommonJS project
  const mm = await loadEsm<typeof import('music-metadata')>('music-metadata');
})();

When you use Node.js version ≥ 22, which supports loading ESM modules via require, this compensates for that issue.

Frequently Asked Questions

How can I traverse (a long) list of files?

What is important that file parsing should be done in a sequential manner. In a plain loop, due to the asynchronous character (like most JavaScript functions), it would cause all the files to run in parallel which is will cause your application to hang in no time. There are multiple ways of achieving this:

  1. Using recursion

    import { parseFile } from 'music-metadata';
    
    function parseFiles(audioFiles) {
    
      const audioFile = audioFiles.shift();
    
      if (audioFile) {
        return parseFile(audioFile).then(metadata => {
          // Do great things with the metadata
          return parseFiles(audioFiles); // process rest of the files AFTER we are finished
        })
      }
    }
    
    
  2. Use async/await

    Use async/await

    import { parseFile } from 'music-metadata';
    
    // it is required to declare the function 'async' to allow the use of await
    async function parseFiles(audioFiles) {
    
        for (const audioFile of audioFiles) {
    
            // await will ensure the metadata parsing is completed before we move on to the next file
            const metadata = await parseFile(audioFile);
            // Do great things with the metadata
        }
    }
    

Using music-metadata with TypeScript and module-resolution set to bundler.

If the TypeScript compiler option moduleResolution is set to "bundler", it does not set the ECMAScript "node" condition, causing the Node specific function fail to import.

This is the case using Next.js. See issue #2370 how to resolve that.

Licence

This project is licensed under the MIT License. Feel free to use, modify, and distribute as needed.

aiff
ape
asf
audio
dsd
flac
id3
m4a
metadata
mp3
mp4
musepack
musicbrainz
ogg
opus
picard
tag
tags
vorbis
wav

Project health

Overall

3.8/10

Maintained

10/10

Code review

0/10
OpenSSF Scorecard

Latest release

12.2.0 · Oct 12, 2026

Releases this year

23

Significant stargazers

Espen Hovlandsdal

672 followers · starred Sep 2019

Jakub T. Jankiewicz

615 followers · starred Dec 2024

Jordan Eldredge

988 followers · starred Jul 2018

Myriad-Dreamin

958 followers · starred Mar 2020