Node.js Blob & File Implementation
fetch-blob provides a robust implementation of the Web Blob and File APIs for Node.js environments, originally forked from `node-fetch`. It is currently at stable version 4.0.0, with frequent minor and patch releases, and major releases addressing breaking changes related to internal architecture or standard compliance. Key differentiators include its ability to handle Blob parts backed by the file system without loading content into memory, and its support for WHATWG streams, requiring explicit conversion for Node.js stream compatibility. While Node.js 18+ includes a native `Blob` class, `fetch-blob` remains relevant for older Node.js versions or for its advanced file system-backed blob capabilities.
Common errors
-
TypeError: Blob is not a constructor
cause Attempting to use `new Blob()` in a CommonJS module after v3.0.0 without proper dynamic import.fixIf in a CommonJS module, use `const { Blob } = await import('fetch-blob');` or migrate your module to ESM. -
ERR_MODULE_NOT_FOUND: Cannot find package 'fetch-blob/file.js' (or similar with 'from.js')
cause Incorrect import path for `File` or file system utilities in an ESM context, possibly missing the `.js` extension or pointing to the wrong entry.fixVerify the import path, ensuring it's `fetch-blob/file.js` for `File` or `fetch-blob/from.js` for `blobFrom` and related functions. Remember the explicit `.js` extension is crucial for ESM. -
TypeError: blob.stream(...).pipe is not a function
cause Trying to pipe the WHATWG `ReadableStream` returned by `blob.stream()` directly as if it were a Node.js `Readable` stream.fixConvert the WHATWG stream to a Node.js `Readable` stream first using `Readable.from(blob.stream())`.
Warnings
- breaking `fetch-blob` v3.0.0 switched entirely to ESM (ECMAScript Modules). CommonJS `require()` is no longer directly supported. This also involved internal changes like using private fields and `TextEncoder`/`Decoder`, requiring Node.js 12+ and 11+ respectively.
- breaking Since v3.0.0, `blob.stream()` now returns a WHATWG-compatible `ReadableStream` (an async iterable) instead of a Node.js `Readable` stream. Direct piping or traditional Node.js stream consumers will break.
- breaking Version 4.0.0 removed the dependency on `streams` polyfill. While this reduces bundle size and external dependencies, ensure your environment correctly handles WHATWG streams or use the `Readable.from()` conversion for Node.js streams.
- gotcha Node.js 18 and later includes a native `Blob` implementation. While `fetch-blob` is still functional, for newer Node.js versions, the native `Blob` might offer better performance or integration. However, `fetch-blob` offers advanced features like file system-backed blobs not present in the native implementation.
- gotcha The `File` class is exported from `fetch-blob/file.js`, not directly from the main package. Similarly, file system utility functions like `blobFrom`, `fileFrom`, `createTemporaryBlob`, etc., are exported from `fetch-blob/from.js`.
Install
-
npm install fetch-blob -
yarn add fetch-blob -
pnpm add fetch-blob
Imports
- Blob
const { Blob } = require('fetch-blob')import { Blob } from 'fetch-blob' - File
import { File } from 'fetch-blob'import { File } from 'fetch-blob/file.js' - fileFromSync
import { fileFromSync } from 'fetch-blob'import { fileFromSync } from 'fetch-blob/from.js' - createTemporaryFile
import { createTemporaryFile } from 'fetch-blob/from.js'
Quickstart
import { Blob } from 'fetch-blob';
import { File } from 'fetch-blob/file.js';
import { blobFromSync, fileFromSync } from 'fetch-blob/from.js';
import { Readable } from 'stream';
import { writeFileSync, existsSync, unlinkSync } from 'fs';
import { join } from 'path';
const testFilePath = join(process.cwd(), 'temp-test-file.txt');
writeFileSync(testFilePath, 'This is a test file content.');
async function runQuickstart() {
// Create a basic Blob from a string
const textBlob = new Blob(['hello, world', ' and some more text'], { type: 'text/plain' });
console.log(`Text Blob size: ${textBlob.size} bytes`);
console.log(`Text Blob content: ${await textBlob.text()}`);
// Create a File from an existing file path, without reading into memory
const fsFile = fileFromSync(testFilePath, 'text/plain');
console.log(`FS File name: ${fsFile.name}`);
console.log(`FS File size: ${fsFile.size} bytes`);
console.log(`FS File last modified: ${new Date(fsFile.lastModified).toISOString()}`);
// Combine multiple Blob/File parts into a new Blob
const combinedBlob = new Blob([textBlob, fsFile, new Uint8Array([1, 2, 3])]);
console.log(`Combined Blob size: ${combinedBlob.size} bytes`);
// Read the combined blob's stream as a Node.js Readable
const nodeStream = Readable.from(combinedBlob.stream());
let streamContent = '';
for await (const chunk of nodeStream) {
streamContent += chunk.toString();
}
console.log(`Combined Blob stream content (partial): ${streamContent.substring(0, 50)}...`);
// Clean up the temporary file
if (existsSync(testFilePath)) {
unlinkSync(testFilePath);
}
}
runQuickstart().catch(console.error);