Download and extract files from URLs with support for archives and HTTP streaming
npx @tessl/cli install tessl/npm-download@8.0.0Download is a Node.js library that provides file downloading and optional archive extraction from URLs. It offers both Promise-based and stream-based APIs with robust HTTP request handling, automatic filename detection, and comprehensive archive format support through the decompress library.
npm install downloadconst download = require('download');const fs = require('fs');
const download = require('download');
(async () => {
// Download and save to directory
await download('https://example.com/file.jpg', 'dist');
// Download and get buffer
const buffer = await download('https://example.com/file.jpg');
fs.writeFileSync('downloaded-file.jpg', buffer);
// Use as stream
download('https://example.com/file.jpg').pipe(fs.createWriteStream('file.jpg'));
// Download and extract archive
await download('https://example.com/archive.zip', 'dist', { extract: true });
})();The download package is built around a single function that returns both a Promise and a Stream:
got library for robust HTTP handling with proxy supportarchive-typeCore functionality for downloading files from URLs with flexible output options.
/**
* Download a file from a URL
* @param uri - URL to download from
* @param output - Optional destination directory path
* @param opts - Optional configuration options
* @returns Stream & Promise<Buffer> - Duplex stream that also acts as a Promise
*/
function download(uri, output?, opts?) : Stream & Promise<Buffer>;Options object that accepts all got HTTP client options plus download-specific settings.
interface DownloadOptions {
/** Whether to extract archive files (default: false) */
extract?: boolean;
/** Custom filename for saved file */
filename?: string;
/** Character encoding for response (default: null for binary) */
encoding?: string | null;
/** Whether to reject unauthorized SSL certificates */
rejectUnauthorized?: boolean;
/** All got HTTP client options are also supported */
[key: string]: any;
}The function returns an object that acts as both a readable stream and a Promise.
interface DownloadReturn extends Stream {
/** Promise interface - resolves to Buffer containing file data */
then<T>(onFulfilled?: (value: Buffer) => T | Promise<T>): Promise<T>;
/** Promise interface - handles promise rejections */
catch<T>(onRejected?: (reason: any) => T | Promise<T>): Promise<T>;
}Inherits all standard Node.js stream events plus additional events from the got HTTP client.
// Standard stream events
download(url).on('data', (chunk) => { /* handle data chunk */ });
download(url).on('end', () => { /* download complete */ });
download(url).on('error', (err) => { /* handle error */ });
// Got-specific events
download(url).on('response', (response) => { /* HTTP response received */ });
download(url).on('request', (request) => { /* HTTP request sent */ });// Basic promise usage
const buffer = await download('https://example.com/file.pdf');
// With error handling
try {
const data = await download('https://example.com/file.zip');
console.log('Downloaded', data.length, 'bytes');
} catch (error) {
console.error('Download failed:', error.message);
}const fs = require('fs');
// Pipe to file
download('https://example.com/large-file.zip')
.pipe(fs.createWriteStream('output.zip'));
// Handle stream events
const stream = download('https://example.com/file.dat');
stream.on('data', chunk => console.log('Received', chunk.length, 'bytes'));
stream.on('end', () => console.log('Download complete'));// Save to directory with original filename
await download('https://example.com/photo.jpg', 'downloads');
// Save with custom filename
await download('https://example.com/file.dat', 'downloads', {
filename: 'renamed-file.dat'
});
// Filename detection from content-disposition header
await download('https://api.example.com/download/123', 'downloads');// Extract zip/tar/etc archives
await download('https://example.com/archive.zip', 'extracted', {
extract: true
});
// Extract with decompress options
await download('https://example.com/archive.tar.gz', 'output', {
extract: true,
strip: 1 // decompress option - remove one level of directories
});// Custom headers
await download('https://api.example.com/file', 'downloads', {
headers: {
'Authorization': 'Bearer token123',
'User-Agent': 'MyApp/1.0'
}
});
// Proxy support
await download('https://example.com/file.zip', 'downloads', {
proxy: 'http://proxy.example.com:8080'
});
// SSL configuration
await download('https://untrusted-ssl.example.com/file', 'downloads', {
rejectUnauthorized: false
});// Download multiple files
await Promise.all([
'https://example.com/file1.jpg',
'https://example.com/file2.png',
'https://example.com/file3.gif'
].map(url => download(url, 'downloads')));
// Download with different options
const downloads = [
{ url: 'https://example.com/doc.pdf', dest: 'documents' },
{ url: 'https://example.com/archive.zip', dest: 'archives', extract: true }
];
await Promise.all(downloads.map(({ url, dest, ...opts }) =>
download(url, dest, opts)
));// HTTP errors (404, 500, etc.)
try {
await download('https://example.com/nonexistent');
} catch (error) {
if (error.response?.statusCode === 404) {
console.log('File not found');
}
}
// Network errors
try {
await download('https://unreachable-server.com/file');
} catch (error) {
if (error.code === 'ENOTFOUND') {
console.log('Server not found');
}
}
// File system errors (permissions, disk space, etc.)
try {
await download('https://example.com/file', '/read-only-directory');
} catch (error) {
if (error.code === 'EACCES') {
console.log('Permission denied');
}
}