TagLib-Wasm
Guide
API Reference
Examples
NPM
GitHub
Guide
API Reference
Examples
NPM
GitHub
  • Getting Started

    • Introduction
    • Installation
    • Quick Start
    • Platform-Specific Examples
  • Features

    • Working with Cover Art
    • Examples
    • Cloudflare Workers Setup
  • Core Concepts

    • Runtime Compatibility
    • Memory Management
    • Performance Guide
    • Error Handling Guide
  • API Reference

    • taglib-wasm API Reference
    • TagLib Tag Name Constants and Cross-Format Mapping
    • Extended Metadata with PropertyMap API
  • Advanced

    • Implementation Guide
    • Troubleshooting Guide
    • Cloudflare Workers
  • Development

    • Testing Guide
    • Future Improvements
    • Publishing Guide

Platform-Specific Examples

This guide shows how to use taglib-wasm in different JavaScript runtime environments. Each platform has slightly different requirements and best practices.

Deno

Deno has native TypeScript support and uses the npm: specifier for npm packages:

import { TagLib } from "npm:taglib-wasm";

// Initialize taglib-wasm
const taglib = await TagLib.initialize();

// Load audio file (can pass file path or buffer)
const file = await taglib.open("song.mp3"); // Direct file path (simpler)
// Or from buffer: const file = await taglib.open(await Deno.readFile("song.mp3"));

// Read metadata
const tags = file.tag();
const props = file.audioProperties();

console.log(`Title: ${tags.title}`);
console.log(`Artist: ${tags.artist}`);
console.log(`Duration: ${props.length}s`);
console.log(`Bitrate: ${props.bitrate} kbps`);

// Write metadata
const tag = file.tag();
tag.setTitle("New Title");
tag.setArtist("New Artist");
tag.setAlbum("New Album");

// Save changes
file.save();

console.log("Updated tags:", file.tag());

// Clean up
file.dispose();

Deno-Specific Tips

  • Use Deno.readFile() for reading files as Uint8Array
  • Use Deno.writeFile() for saving modified buffers
  • Permissions: --allow-read and --allow-write are required for file operations

Node.js

Node.js requires the TypeScript loader (tsx) or native TypeScript support (Node.js 22.6+):

import { TagLib } from "taglib-wasm";
import { readFile } from "fs/promises";

// Initialize taglib-wasm
const taglib = await TagLib.initialize();

// Load audio file (can pass file path or buffer)
const file = await taglib.open("song.mp3"); // Direct file path (simpler)
// Or from buffer: const file = await taglib.open(await readFile("song.mp3"));

// Read metadata
const tags = file.tag();
const props = file.audioProperties();

console.log(`Title: ${tags.title}`);
console.log(`Artist: ${tags.artist}`);
console.log(`Duration: ${props.length}s`);
console.log(`Bitrate: ${props.bitrate} kbps`);

// Write metadata
const tag = file.tag();
tag.setTitle("New Title");
tag.setArtist("New Artist");
tag.setAlbum("New Album");

// Save changes
file.save();

console.log("Updated tags:", file.tag());

// Clean up
file.dispose();

Node.js-Specific Tips

  • Use fs.promises for async file operations
  • For Node.js < 22.6, use tsx: npx tsx script.ts
  • For Node.js 22.6+: node --experimental-strip-types script.ts
  • For Node.js 23.6+: node script.ts (no flag needed)

Bun

Bun has native TypeScript support and optimized file APIs:

import { TagLib } from "taglib-wasm";

// Initialize taglib-wasm
const taglib = await TagLib.initialize();

// Load audio file (can pass file path or buffer)
const file = await taglib.open("song.mp3"); // Direct file path (simpler)
// Or from buffer: const file = await taglib.open(new Uint8Array(await Bun.file("song.mp3").arrayBuffer()));

// Read metadata
const tags = file.tag();
const props = file.audioProperties();

console.log(`Title: ${tags.title}`);
console.log(`Artist: ${tags.artist}`);
console.log(`Duration: ${props.length}s`);
console.log(`Bitrate: ${props.bitrate} kbps`);

// Write metadata
const tag = file.tag();
tag.setTitle("New Title");
tag.setArtist("New Artist");
tag.setAlbum("New Album");

// Save changes
file.save();

console.log("Updated tags:", file.tag());

// Clean up
file.dispose();

Bun-Specific Tips

  • Use Bun.file() for optimized file operations
  • Use Bun.write() for saving files
  • Bun's performance is excellent for processing many files

Browser

Browsers require loading files via File API or fetch:

import { TagLib } from "taglib-wasm";

// Initialize taglib-wasm
const taglib = await TagLib.initialize();

// Load from file input or fetch
const fileInput = document.querySelector('input[type="file"]');
const audioFile = fileInput.files[0];
const audioData = new Uint8Array(await audioFile.arrayBuffer());
const file = await taglib.open(audioData); // Browser requires buffer

// Read metadata
const tags = file.tag();
const props = file.audioProperties();

console.log(`Title: ${tags.title}`);
console.log(`Artist: ${tags.artist}`);
console.log(`Duration: ${props.length}s`);
console.log(`Bitrate: ${props.bitrate} kbps`);

// Write metadata
const tag = file.tag();
tag.setTitle("New Title");
tag.setArtist("New Artist");
tag.setAlbum("New Album");

// Save changes
file.save();

console.log("Updated tags:", file.tag());

// Clean up
file.dispose();

Browser-Specific Tips

  • Always load from ArrayBuffer/Uint8Array (no file path support)
  • Use FileReader API for file inputs
  • Use fetch() for remote files
  • Consider using a bundler (Vite, Webpack, Parcel)
  • For downloads, create a Blob and use URL.createObjectURL()

Example: Complete Browser Application

<!DOCTYPE html>
<html>
  <head>
    <title>Audio Metadata Editor</title>
  </head>
  <body>
    <input type="file" id="fileInput" accept="audio/*">
    <div id="metadata"></div>

    <script type="module">
      import { TagLib } from "taglib-wasm";

      const fileInput = document.getElementById("fileInput");
      const metadataDiv = document.getElementById("metadata");

      fileInput.addEventListener("change", async (event) => {
        const file = event.target.files[0];
        if (!file) return;

        const taglib = await TagLib.initialize();
        const audioData = new Uint8Array(await file.arrayBuffer());
        const audioFile = await taglib.open(audioData);

        const tags = audioFile.tag();
        const props = audioFile.audioProperties();

        metadataDiv.innerHTML = `
                <h3>Metadata:</h3>
                <p>Title: ${tags.title || "Unknown"}</p>
                <p>Artist: ${tags.artist || "Unknown"}</p>
                <p>Album: ${tags.album || "Unknown"}</p>
                <p>Duration: ${props.length}s</p>
                <p>Bitrate: ${props.bitrate} kbps</p>
            `;

        audioFile.dispose();
      });
    </script>
  </body>
</html>

Cloudflare Workers

Workers require the special workers import and memory configuration:

import { TagLib } from "taglib-wasm/workers";

export default {
  async fetch(request: Request): Promise<Response> {
    if (request.method === "POST") {
      try {
        // Initialize taglib-wasm with Workers-specific configuration
        // See docs/Cloudflare-Workers.md for memory configuration details
        const taglib = await TagLib.initialize({
          memory: { initial: 8 * 1024 * 1024 }, // 8MB for Workers
        });

        // Get audio data from request
        const audioData = new Uint8Array(await request.arrayBuffer());
        const file = await taglib.open(audioData); // Workers require buffer

        // Read metadata
        const tags = file.tag();
        const props = file.audioProperties();

        // Extract metadata
        const metadata = {
          title: tags.title,
          artist: tags.artist,
          album: tags.album,
          year: tags.year,
          genre: tags.genre,
          duration: props.length,
          bitrate: props.bitrate,
          format: file.getFormat(),
        };

        // Clean up
        file.dispose();

        return Response.json({
          success: true,
          metadata,
          fileSize: audioData.length,
        });
      } catch (error) {
        return Response.json({
          error: "Failed to process audio file",
          message: (error as Error).message,
        }, { status: 500 });
      }
    }

    return new Response("Send POST request with audio file", { status: 400 });
  },
};

Workers-Specific Tips

  • Use the /workers import path for optimized Workers build
  • Configure memory limits (Workers have 128MB limit)
  • Always load from ArrayBuffer (no file system)
  • Consider using Durable Objects for caching
  • See Cloudflare Workers Guide for detailed configuration

Electron

Electron supports both main and renderer processes:

Main Process

import { TagLib } from "taglib-wasm";
import { readFile } from "fs/promises";

async function getMetadata(filePath: string) {
  const taglib = await TagLib.initialize();
  const file = await taglib.open(filePath);

  const tags = file.tag();
  const props = file.audioProperties();

  const metadata = {
    title: tags.title,
    artist: tags.artist,
    album: tags.album,
    duration: props.length,
    bitrate: props.bitrate,
  };

  file.dispose();
  return metadata;
}

// IPC handler
ipcMain.handle("get-metadata", async (event, filePath) => {
  return await getMetadata(filePath);
});

Renderer Process

// With nodeIntegration: true
const { TagLib } = require("taglib-wasm");

// Or with preload script
const metadata = await window.api.getMetadata(filePath);

Electron-Specific Tips

  • Works in both main and renderer processes
  • Use IPC for secure file operations
  • Consider preload scripts for security
  • Bundle size matters less in Electron apps

Performance Tips by Platform

PlatformBest PracticeNotes
DenoUse file paths directlyFastest file I/O
Node.jsUse streams for large filesGood for batch processing
BunUse Bun.file() APIOptimized native performance
BrowserProcess in Web WorkersPrevents UI blocking
WorkersMinimize memory usage128MB limit per request
ElectronUse main process for I/OBetter performance than renderer

Common Patterns

Batch Processing (Node.js/Deno/Bun)

import { glob } from "glob";
import { TagLib } from "taglib-wasm";

const taglib = await TagLib.initialize();
const files = await glob("music/**/*.mp3");

for (const filePath of files) {
  const file = await taglib.open(filePath);
  const tags = file.tag();

  console.log(`${filePath}: ${tags.artist} - ${tags.title}`);

  file.dispose();
}

Progress Tracking (Browser)

async function processFiles(
  files: FileList,
  onProgress: (percent: number) => void,
) {
  const taglib = await TagLib.initialize();

  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    const audioData = new Uint8Array(await file.arrayBuffer());
    const audioFile = await taglib.open(audioData);

    // Process file...

    audioFile.dispose();
    onProgress((i + 1) / files.length * 100);
  }
}

Next Steps

  • Check out the Examples for more code samples
  • Read the API Reference for detailed documentation
  • See Runtime Compatibility for platform-specific details
Edit this page on GitHub
Last Updated:: 6/17/25, 3:55 AM
Contributors: Charles Wiltgen, Claude
Prev
Quick Start