npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alberteinshutoin/lazy-image

v0.16.0

Published

Web image optimization engine for Node.js - smaller JPEG files in simple canonical benchmarks, powered by Rust + mozjpeg

Readme

lazy-image 🦀

Web image optimization engine for Node.js. Rust core, smaller JPEG outputs, bounded memory.

In current canonical benchmarks, lazy-image produces 17-20% smaller JPEG outputs than sharp for the two simple PNG → JPEG cases: no-resize conversion and resize-to-800px. AVIF/WebP size and speed, and multi-operation JPEG pipelines, are workload-specific; benchmark your target image mix before assuming a win.

  • Not a drop-in replacement for sharp — use sharp if you need its full API or maximum throughput.
  • Security-first: Metadata stripped by default; keepMetadata() to preserve. File-path inputs (fromPath()/processBatch()toFile()) bypass the V8 heap — small/medium files (≤ 256 MB) are read into Rust-owned memory for SIGBUS safety; only files larger than 256 MB use mmap with advisory locks. See docs/ZERO_COPY.md.
  • Japanese: README.ja.md. mmap (files > 256 MB): do not modify or delete source files while processing; use a copy or from(Buffer) for mutable inputs.
  • Lazy contract: docs/LAZY_SEMANTICS.md explains what is deferred vs eager.
  • Metadata matrix: docs/METADATA_SUPPORT.md.
  • Philosophy and non-goals: docs/PROJECT_PHILOSOPHY.md.

npm version npm downloads Node.js CI codecov License: MIT Rust


Quick Start (5 lines)

const { ImageEngine } = require('@alberteinshutoin/lazy-image');

const bytesWritten = await ImageEngine.fromPath('input.png')
  .resize(800)
  .toFile('output.jpg', 'jpeg', 80);

console.log(`Wrote ${bytesWritten} bytes`);

Architecture Overview

src/                        # selected high-level Rust core modules
├── engine/
│   ├── api/                # ImageEngine public API + NAPI-facing operations
│   ├── pipeline/           # Operation application, color state, capabilities, optimization
│   ├── tasks/              # NAPI async task contexts and encode/batch/write execution
│   ├── memory/             # Cgroup detection, memory estimates, weighted semaphore
│   ├── io/                 # File sources, mmap, ICC/EXIF extraction and embedding
│   ├── resize.rs           # Dimension calc, fast_image_resize dispatch
│   ├── encoder.rs          # JPEG/PNG/WebP/AVIF encoding + ICC/EXIF embedding
│   ├── decoder.rs          # Format detection + decoding
│   ├── firewall.rs         # Input sanitization policies
│   ├── metadata.rs         # Metadata policy and preservation state
│   └── validation.rs       # Input, operation, and output validation helpers
├── ops.rs                  # Operation enum, presets, output formats
├── error.rs                # 4-tier error taxonomy (E1xx–E9xx)
└── codecs/avif_safe.rs     # Safe libavif FFI wrappers

lib/helpers.js              # Encoding profiles, target-bytes binary search
streaming/pipeline.js       # Disk-backed bounded-memory streaming

Key design decisions: lazy execution (ops queue until output), file-path inputs bypass the V8 heap (read-into-memory for ≤ 256 MB, mmap with advisory locks for > 256 MB), memory-bounded concurrency via weighted semaphore, panic guards on all codec entry points. See docs/ARCHITECTURE.md for details.


Choose lazy-image if / Choose sharp if

| Choose lazy-image if | Choose sharp if | |---|---| | You pay for bandwidth (CDN, S3, CloudFront) | You need maximum encoding throughput | | You run in serverless / memory-constrained envs | You need a broad image editing API | | You want AVIF with safe defaults | You need drop-in API compatibility | | You want smaller JPEG outputs over broader codec throughput | You need GIF, SVG, or TIFF support |

Key differentiators:

  1. JPEG file size optimization — mozjpeg produces 17-20% smaller JPEG outputs in the canonical simple PNG → JPEG no-resize and resize benchmarks
  2. Memory efficiency — file-path inputs are not copied into the V8 heap; decoded pixels stay in Rust memory
  3. Security-first — GPS auto-strip, Image Firewall, Rust memory safety
  4. AVIF output support — libavif encoder with quality-tuned defaults and ICC support; benchmark AVIF workloads for size/speed

What lazy-image does NOT compete on: raw encoding speed (sharp/libvips is faster), feature breadth (no drawing, compositing, or GIF), API compatibility with sharp.

Project philosophy: optimize for smaller web outputs, bounded memory, and safe defaults first. Any speed claims must be codec- and workload-specific, not a blanket "faster than sharp" promise.

Benchmarks and details: docs/PERFORMANCE.md. Full compatibility matrix: docs/COMPATIBILITY.md.


Recommended Paths

Start with one of these workflows:

  • Web delivery optimization: fromPath() -> resize()/crop() -> toFile() for the lowest heap usage and the clearest operational path
  • Upload sanitization: fromPath() -> sanitize({ policy: 'strict' }) -> toFile()/toBuffer() for untrusted user uploads
  • Build-time / batch generation: processBatch() or clone() for static sites, media pipelines, and multi-output generation
  • Final optimization after editing: use sharp/ImageMagick for compositing, filters, or animation, then pass the result through lazy-image for final JPEG/WebP/AVIF optimization

Scenario guide: docs/ADOPTION_GUIDE.md.


Cost Savings Example (ROI)

Assume:

  • average image size before optimization: 1.0 MB
  • average JPEG-oriented reduction with lazy-image: 18% (example only; not universal across all codecs)
  • CDN transfer rate: $0.085/GB (example: CloudFront pay-as-you-go, US/EU next 9TB tier)

| Scenario | Transfer with sharp | Transfer with lazy-image | Monthly savings | |---|---:|---:|---:| | 1M image deliveries / month | 976.6 GB | 800.8 GB | $14.94 | | 10M image deliveries / month | 9.54 TB | 7.82 TB | $149.41 | | 100M image deliveries / month | 95.37 TB | 78.20 TB | $1,494.14 |

Break-even intuition:

  • Encoding overhead is paid once per generated image
  • Bandwidth savings are realized every time the image is delivered
  • If each generated image is viewed multiple times, lazy-image generally wins quickly

Use the interactive calculator:


Installation

npm install @alberteinshutoin/lazy-image

Platform-specific binaries (~6–9 MB per platform) are installed automatically. Build from source: npm run build. See docs/PERFORMANCE.md for package size comparison with sharp.


Basic Usage

Resize and save (recommended: file-to-file)

await ImageEngine.fromPath('photo.jpg')
  .resize({ width: 800, fit: 'inside' }) // positional args also supported
  .toFile('thumb.jpg', 'jpeg', 85);

Format conversion (e.g. PNG → WebP/AVIF)

const buffer = await ImageEngine.fromPath('input.png')
  .resize({ width: 600 })
  .toBuffer('webp', 80);

Metadata without decoding

const { inspectFile } = require('@alberteinshutoin/lazy-image');
const meta = inspectFile('input.jpg'); // { width, height, format }

lazy-image defers full pixel decode, transforms, and encoding until toBuffer() / toFile(). Constructors still do source setup and metadata extraction; see docs/LAZY_SEMANTICS.md.

More: batch processing, presets, metrics, streaming — docs/API.md.


Documentation

| Topic | Link | |-------|------| | Examples | examples/ | | TypeScript guide | docs/TYPESCRIPT.md | | Full API reference | docs/API.md | | Migration from sharp | docs/MIGRATION_FROM_SHARP.md | | Performance & when to use | docs/PERFORMANCE.md | | Architecture & security | docs/ARCHITECTURE.md | | Troubleshooting | docs/TROUBLESHOOTING.md | | Security policy & reporting | SECURITY.md | | Roadmap & scope | docs/ROADMAP.md | | Adoption guide / recommended workflows | docs/ADOPTION_GUIDE.md | | Wasm / browser / Edge strategy | docs/WASM_STRATEGY.md | | Wasm package and policy API | docs/WASM_PACKAGE_API.md | | Wasm upload benchmark guidance | docs/WASM_BENCHMARKING.md | | Metadata support matrix | docs/METADATA_SUPPORT.md | | ROI calculator methodology | docs/ROI_CALCULATOR.md | | Version history | docs/VERSION_HISTORY.md | | Specification (spec/) | spec/pipeline.md, spec/resize.md, spec/errors.md, spec/limits.md, spec/quality.md, spec/metadata.md | | Error codes | docs/ERROR_CODES.md | | Benchmarks (raw data) | docs/TRUE_BENCHMARKS.md | | Binary size comparison (AVIF on/off) | docs/BINARY_SIZE.md | | Benchmark snapshots log | docs/BENCHMARK_RESULTS.md | | Benchmark operations | docs/BENCHMARK_OPERATIONS.md |


Features (summary)

Smaller JPEG (mozjpeg) · WebP (libwebp) · AVIF (libavif) · ICC profiles · EXIF auto-orient · Bypass-V8-heap file I/O (read-into-memory ≤ 256 MB, mmap > 256 MB) · Disk-backed bounded-memory pipeline (createStreamingPipeline(), not true chunked transform streaming) · Image Firewall · GPS auto-strip · Fluent API · Rust core (NAPI-RS) · Cross-platform (macOS, Windows, Linux). Design choices and limits: docs/ROADMAP.md and docs/ARCHITECTURE.md.


Development

npm install && npm run build
npm test

See CONTRIBUTING.md for workflow, test commands, and contribution guidelines. Benchmark testing: lazy-image-test Docker environment. Fuzzing: FUZZING.md.


License

MIT


Credits

mozjpeg · libwebp · libavif · fast_image_resize · img-parts · napi-rs


Ship it. 🚀