High performance Node.js image processing library for resizing JPEG, PNG, WebP, GIF, AVIF and TIFF images
80
Sharp provides extensive utilities for performance monitoring, library configuration, and runtime optimization controls.
Control libvips operation cache for memory and performance optimization.
/**
* Get or set libvips operation cache limits
* @param options - Cache configuration or boolean
* @returns Current cache statistics
*/
sharp.cache(options?: boolean | CacheOptions): CacheResult;
interface CacheOptions {
/** Maximum memory in MB (default 50) */
memory?: number;
/** Maximum open files (default 20) */
files?: number;
/** Maximum cached operations (default 100) */
items?: number;
}
interface CacheResult {
/** Memory usage statistics */
memory: {
current: number;
high: number;
max: number;
};
/** File handle statistics */
files: {
current: number;
max: number;
};
/** Cached items statistics */
items: {
current: number;
max: number;
};
}Usage Examples:
// Get current cache statistics
const cacheStats = sharp.cache();
console.log('Memory usage:', cacheStats.memory);
console.log('Open files:', cacheStats.files);
console.log('Cached items:', cacheStats.items);
// Set cache limits
sharp.cache({
memory: 100, // 100MB
files: 50, // 50 open files
items: 200 // 200 cached operations
});
// Disable caching
sharp.cache(false);
// Reset to defaults
sharp.cache(true);
// Monitor cache usage
const monitorCache = () => {
const stats = sharp.cache();
console.log(`Memory: ${stats.memory.current}MB / ${stats.memory.max}MB`);
console.log(`Files: ${stats.files.current} / ${stats.files.max}`);
console.log(`Items: ${stats.items.current} / ${stats.items.max}`);
if (stats.memory.current > stats.memory.max * 0.9) {
console.warn('Cache memory usage is high');
}
};Manage thread usage for optimal performance across different workloads.
/**
* Get or set number of libvips worker threads
* @param concurrency - Number of threads (0 = auto-detect)
* @returns Current concurrency value
*/
sharp.concurrency(concurrency?: number): number;Usage Examples:
// Get current thread count
const currentThreads = sharp.concurrency();
console.log(`Current threads: ${currentThreads}`);
// Set thread count
sharp.concurrency(4); // Use 4 threads
sharp.concurrency(0); // Auto-detect (default)
// Optimize for workload
const optimizeForWorkload = (type) => {
const cpuCount = require('os').cpus().length;
switch (type) {
case 'batch':
// High throughput batch processing
sharp.concurrency(cpuCount);
break;
case 'server':
// Web server with many concurrent requests
sharp.concurrency(Math.max(2, cpuCount / 2));
break;
case 'single':
// Single image processing
sharp.concurrency(1);
break;
default:
// Auto-detect
sharp.concurrency(0);
}
};Monitor Sharp's internal task queue and processing status.
/**
* Access internal task counters
* @returns Current task queue statistics
*/
sharp.counters(): SharpCounters;
interface SharpCounters {
/** Tasks waiting for worker threads */
queue: number;
/** Tasks currently being processed */
process: number;
}Usage Examples:
// Monitor task queue
const monitorTasks = () => {
const counters = sharp.counters();
console.log(`Queued: ${counters.queue}, Processing: ${counters.process}`);
if (counters.queue > 10) {
console.warn('High queue depth - consider increasing concurrency');
}
};
// Monitor during batch processing
const processBatch = async (images) => {
console.log('Starting batch processing...');
const interval = setInterval(monitorTasks, 1000);
try {
await Promise.all(images.map(processImage));
} finally {
clearInterval(interval);
console.log('Batch processing complete');
}
};Enable or disable SIMD vector unit instructions for performance optimization.
/**
* Get or set SIMD vector unit instruction usage
* @param enable - Enable SIMD instructions (optional)
* @returns Current SIMD status
*/
sharp.simd(enable?: boolean): boolean;Usage Examples:
// Check SIMD availability
const simdEnabled = sharp.simd();
console.log(`SIMD enabled: ${simdEnabled}`);
// Enable SIMD (if supported)
if (sharp.simd(true)) {
console.log('SIMD enabled for better performance');
} else {
console.log('SIMD not available on this system');
}
// Disable SIMD for debugging
sharp.simd(false);
// Performance comparison
const benchmarkSIMD = async (imagePath) => {
const image = sharp(imagePath);
// Test with SIMD disabled
sharp.simd(false);
const start1 = Date.now();
await image.clone().resize(800, 600).blur(2).toBuffer();
const time1 = Date.now() - start1;
// Test with SIMD enabled
sharp.simd(true);
const start2 = Date.now();
await image.clone().resize(800, 600).blur(2).toBuffer();
const time2 = Date.now() - start2;
console.log(`Without SIMD: ${time1}ms`);
console.log(`With SIMD: ${time2}ms`);
console.log(`Performance gain: ${((time1 - time2) / time1 * 100).toFixed(1)}%`);
};Block or unblock specific libvips operations for security or compatibility.
/**
* Block libvips operations at runtime
* @param options - Operations to block
*/
sharp.block(options: { operation: string[] }): void;
/**
* Unblock libvips operations at runtime
* @param options - Operations to unblock
*/
sharp.unblock(options: { operation: string[] }): void;Usage Examples:
// Block potentially unsafe operations
sharp.block({
operation: ['VipsForeignLoadTiff', 'VipsForeignLoadPdf']
});
// Create allowlist by blocking all then unblocking specific operations
sharp.block({
operation: ['VipsForeignLoad'] // Block all loaders
});
sharp.unblock({
operation: [
'VipsForeignLoadJpegFile',
'VipsForeignLoadPngFile',
'VipsForeignLoadWebpFile'
]
});
// Security-focused configuration
const secureConfiguration = () => {
// Block operations that could be security risks
sharp.block({
operation: [
'VipsForeignLoadTiff', // TIFF can contain exploits
'VipsForeignLoadPdf', // PDF processing
'VipsForeignLoadSvg', // SVG can contain scripts
'VipsForeignLoadGif' // Limit GIF processing
]
});
// Set conservative limits
sharp.cache({
memory: 50, // Limit memory usage
files: 10, // Limit open files
items: 50 // Limit cached items
});
// Single thread for predictable behavior
sharp.concurrency(1);
};Access version information and format capabilities.
// Static properties providing library information
/** Available input/output formats and their capabilities */
sharp.format: FormatEnum;
/** Version information for Sharp and dependencies */
sharp.versions: {
sharp: string;
vips: string;
// Optional dependency versions
aom?: string;
cairo?: string;
exif?: string;
fontconfig?: string;
freetype?: string;
heif?: string;
jpeg?: string;
lcms?: string;
png?: string;
svg?: string;
tiff?: string;
webp?: string;
// ... other optional dependencies
};
/** Available interpolation methods */
sharp.interpolators: {
nearest: 'nearest';
bilinear: 'bilinear';
bicubic: 'bicubic';
locallyBoundedBicubic: 'lbb';
nohalo: 'nohalo';
vertexSplitQuadraticBasisSpline: 'vsqbs';
};
/** Event emitter for queue status changes */
sharp.queue: NodeJS.EventEmitter;
/** Gravity constants for positioning */
sharp.gravity: GravityEnum;
/** Strategy constants for cropping */
sharp.strategy: StrategyEnum;
/** Kernel constants for resizing */
sharp.kernel: KernelEnum;
/** Fit constants for resize behavior */
sharp.fit: FitEnum;
/** Boolean operation constants */
sharp.bool: BoolEnum;Usage Examples:
// Check format support
console.log('Supported formats:');
Object.keys(sharp.format).forEach(format => {
const info = sharp.format[format];
console.log(`${format}: input=${info.input.file}, output=${info.output.file}`);
});
// Check specific format capabilities
if (sharp.format.avif && sharp.format.avif.output.file) {
console.log('AVIF output is supported');
} else {
console.log('AVIF output not available');
}
// Version information
console.log('Library versions:');
console.log(`Sharp: ${sharp.versions.sharp}`);
console.log(`libvips: ${sharp.versions.vips}`);
if (sharp.versions.webp) {
console.log(`WebP: ${sharp.versions.webp}`);
}
// Check for optional features
const checkFeatures = () => {
const features = {
avif: !!sharp.versions.heif, // AVIF requires HEIF support
svg: !!sharp.versions.svg,
pdf: !!sharp.versions.poppler || !!sharp.versions.pdfium,
tiff: !!sharp.versions.tiff,
jpeg2000: !!sharp.versions.openjpeg
};
console.log('Available features:', features);
return features;
};
// Monitor queue events
sharp.queue.on('change', (queueLength) => {
console.log(`Queue length changed: ${queueLength}`);
});Optimal Configuration for Different Use Cases:
// Web server configuration
const configureForWebServer = () => {
const cpuCount = require('os').cpus().length;
sharp.cache({
memory: 100, // 100MB cache
files: Math.min(cpuCount * 2, 20), // Reasonable file limit
items: 200 // Cache many operations
});
sharp.concurrency(Math.max(2, cpuCount / 2)); // Leave CPU for other tasks
sharp.simd(true); // Enable SIMD if available
// Monitor performance
setInterval(() => {
const stats = sharp.cache();
const counters = sharp.counters();
if (stats.memory.current > stats.memory.max * 0.8) {
console.warn('Sharp cache memory usage high');
}
if (counters.queue > 5) {
console.warn('Sharp queue backing up');
}
}, 30000);
};
// Batch processing configuration
const configureForBatch = () => {
const totalMemory = require('os').totalmem() / 1024 / 1024 / 1024; // GB
const memoryLimit = Math.min(Math.floor(totalMemory / 4), 500); // 25% of RAM, max 500MB
sharp.cache({
memory: memoryLimit,
files: 100, // Many files for batch processing
items: 1000 // Cache many operations
});
sharp.concurrency(0); // Use all available CPUs
sharp.simd(true); // Maximum performance
};
// Memory-constrained configuration
const configureForLowMemory = () => {
sharp.cache({
memory: 20, // Low memory limit
files: 5, // Few open files
items: 50 // Limited caching
});
sharp.concurrency(1); // Single thread to limit memory
sharp.simd(false); // Reduce complexity
};Performance Monitoring:
const createPerformanceMonitor = () => {
const stats = {
processedImages: 0,
totalTime: 0,
errors: 0
};
const monitor = {
async processImage(imagePath, operations) {
const startTime = Date.now();
try {
let pipeline = sharp(imagePath);
// Apply operations
for (const op of operations) {
pipeline = pipeline[op.method](...op.args);
}
const result = await pipeline.toBuffer();
const endTime = Date.now();
const processingTime = endTime - startTime;
stats.processedImages++;
stats.totalTime += processingTime;
// Log performance metrics
const avgTime = stats.totalTime / stats.processedImages;
console.log(`Processed ${imagePath} in ${processingTime}ms (avg: ${avgTime.toFixed(1)}ms)`);
return result;
} catch (error) {
stats.errors++;
console.error(`Error processing ${imagePath}:`, error.message);
throw error;
}
},
getStats() {
return {
...stats,
averageTime: stats.processedImages > 0 ? stats.totalTime / stats.processedImages : 0,
errorRate: stats.processedImages > 0 ? stats.errors / stats.processedImages : 0
};
},
reset() {
stats.processedImages = 0;
stats.totalTime = 0;
stats.errors = 0;
}
};
return monitor;
};Memory Management:
const createMemoryManager = () => {
return {
async processWithMemoryManagement(images, processor) {
const batchSize = 10; // Process in batches
const results = [];
for (let i = 0; i < images.length; i += batchSize) {
const batch = images.slice(i, i + batchSize);
// Process batch
const batchResults = await Promise.all(
batch.map(processor)
);
results.push(...batchResults);
// Check memory usage
const cacheStats = sharp.cache();
if (cacheStats.memory.current > cacheStats.memory.max * 0.8) {
console.log('Clearing cache due to high memory usage');
sharp.cache(false); // Clear cache
sharp.cache(true); // Re-enable with defaults
}
// Force garbage collection if available
if (global.gc) {
global.gc();
}
console.log(`Processed batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(images.length/batchSize)}`);
}
return results;
}
};
};Complete definitions for all Sharp constants and enums.
interface FormatEnum {
heif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
jpeg: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
jp2: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
jxl: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
png: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
webp: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
gif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
avif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
tiff: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
dz: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
fits: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
magick: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
openslide: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
pdf: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
ppm: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
raw: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
svg: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
v: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
}
interface GravityEnum {
north: 1;
northeast: 2;
east: 3;
southeast: 4;
south: 5;
southwest: 6;
west: 7;
northwest: 8;
center: 9;
centre: 9;
}
interface StrategyEnum {
entropy: 16;
attention: 17;
}
interface KernelEnum {
nearest: 'nearest';
linear: 'linear';
cubic: 'cubic';
mitchell: 'mitchell';
lanczos2: 'lanczos2';
lanczos3: 'lanczos3';
}
interface FitEnum {
contain: 'contain';
cover: 'cover';
fill: 'fill';
inside: 'inside';
outside: 'outside';
}
interface BoolEnum {
and: 'and';
or: 'or';
eor: 'eor';
}
interface Interpolators {
nearest: 'nearest';
bilinear: 'bilinear';
bicubic: 'bicubic';
locallyBoundedBicubic: 'lbb';
nohalo: 'nohalo';
vertexSplitQuadraticBasisSpline: 'vsqbs';
}Install with Tessl CLI
npx tessl i tessl/npm-sharpdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10