> [!NOTE]
> This README was generated by [SKILL](https://github.com/agenvoy/skill-readme-generate), get the ZH version from [here](https://github.com/pardnio/node-image-server/blob/master/doc/README.zh.md).

***

<p align="center">
<strong>RESIZE ONCE, SERVE FROM CACHE EVERYWHERE!</strong>
</p>

<p align="center">
<a href="https://github.com/pardnio/node-image-server/releases"><img src="https://img.shields.io/github/v/tag/pardnio/node-image-server?include_prereleases&style=for-the-badge" alt="Version"></a>
<a href="https://github.com/pardnio/node-image-server/blob/master/LICENSE"><img src="https://img.shields.io/github/license/pardnio/node-image-server?include_prereleases&style=for-the-badge" alt="License"></a>
</p>

***

> A Node.js image resizing server with on-the-fly WebP/AVIF conversion, Nginx and CDN caching, and date-sorted trash

## Table of Contents

- [Features](#features)
- [Architecture](#architecture)
- [License](#license)
- [Author](#author)

## Features

> `docker compose up -d` · [Documentation](https://github.com/pardnio/node-image-server/blob/master/doc/doc.md)

- **Four-Tier Caching** — Browser, Cloudflare Worker, Nginx `proxy_cache`, and on-disk cache files intercept requests layer by layer, so each image is processed only once.
- **On-the-Fly Resizing** — URL parameters set size, quality, and format (WebP/AVIF/JPG/PNG), defaulting to WebP and shrinking oversized images to a 1024px long edge.
- **Parameterized Cache Variants** — Every size and quality combination produces its own cache file, and the Worker keys its cache on the query string, so variants never overwrite each other.
- **Date-Sorted Trash** — Deletion moves files into `.trash/YYYY-MM-DD/` and returns the new location, making recovery by deletion date straightforward.
- **One-Command Deployment** — Docker Compose starts Nginx alongside a PM2-managed Node.js cluster that respawns workers when they exit.

## Architecture

> [Full Architecture](https://github.com/pardnio/node-image-server/blob/master/doc/architecture.md)

```mermaid
graph TB
    Client[Client] --> Worker[Cloudflare Worker<br>CDN cache]
    Client --> Nginx[Nginx<br>proxy_cache]
    Worker --> Nginx
    Nginx --> App[Express Cluster]
    App --> GET[GET /c/img<br>sharp conversion]
    App --> POST[POST /upload]
    App --> DEL[DELETE /del]
    GET --> Storage[(storage/image<br>upload · cache)]
    POST --> Storage
    DEL --> Trash[(upload/.trash)]
```

## License

This project is licensed under the [MIT LICENSE](https://github.com/pardnio/node-image-server/blob/master/LICENSE).

## Author

Just [open an issue](https://github.com/pardnio/node-image-server/issues/new) to share an idea.

<a href="https://github.com/pardnio/node-image-server/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=pardnio/node-image-server&cache_bust=2026-10-07" alt="node-image-server contributors" />
</a>

***

©️ 2025 [邱敬幃 Pardn Chiu](https://www.linkedin.com/in/pardnchiu)
