Self-hostable image compression, conversion, and background removal. Drop-in API and web UI for shrinking images, switching formats, and stripping backgrounds — built to run on your own server in under a minute.
Most image-optimization SaaS forces you to upload your images to someone else's servers, slap watermarks on the result, or paywall the formats you actually want (AVIF, target-size fitting). Feather is the boring, useful alternative:
- Self-hosted — one Docker image, no external services required to run the core features.
- Fast — built on
sharp(libvips) withmozjpeg,WebP, andAVIFencoders. - Smart — target a file size in MB and Feather binary-searches quality + resize until it fits.
- Private by default — uploads live in a temp dir, get cleaned up automatically, and never leave your box.
- Three modes in one app — compress, convert, and remove background.
- Open API — every web feature is also a REST endpoint you can
curl.
| Capability | Description |
|---|---|
| Compress | Quality slider, target file size in MB, optional resize, metadata stripping |
| Convert | Cross-encode JPEG / PNG / WebP / AVIF with quality + effort controls |
| Remove background | Client-side MODNet ONNX model, no server roundtrip for inference |
| Editor | Crop, rotate, flip, brightness/contrast/saturation, blur, sharpen, grayscale |
| Before/after slider | Compare original vs. output pixel-for-pixel |
| REST API | /api/compress, /api/convert, /api/health, /api/formats |
| Rate limiting | Per-IP, configurable per minute |
| Security headers | CSP, COOP, COEP, X-Frame-Options, X-Content-Type-Options |
| Health check | /api/health returns version + env, ideal for container orchestrators |
| Docker-ready | Multi-stage Alpine image with tini, non-root user, healthcheck baked in |
Supported input formats: JPEG, PNG, WebP, AVIF, SVG, HEIC, HEIF, TIFF, GIF, BMP. Supported output formats: JPEG, PNG, WebP, AVIF.
git clone https://github.com/your-org/feather.git
cd feather
cp .env.example .env
docker compose -f compose/docker-compose.yml up -d --buildOpen http://localhost:3000 and you're running. The first request to background-removal will fetch the MODNet model (~25 MB quantized) and cache it in the feather-models volume, so subsequent restarts are instant.
To use a HuggingFace token (for private model mirrors or to avoid anonymous rate limits):
echo "HUGGINGFACE_TOKEN=hf_xxxxx" >> .env
docker compose -f compose/docker-compose.yml up -dRequires Node ≥ 22 and pnpm ≥ 10.
pnpm install
pnpm run fixtures:generate # one-time test fixtures
pnpm run dev # http://localhost:3000docker compose -f compose/docker-compose.dev.yml upSource is bind-mounted, so edits hot-reload inside the container.
All endpoints accept and return JSON unless otherwise noted. Image upload endpoints take multipart/form-data.
curl -X POST http://localhost:3000/api/compress \
-F "file=@photo.jpg" \
-F "outputFormat=webp" \
-F "quality=80" \
--output compressed.webpTarget a specific file size:
curl -X POST http://localhost:3000/api/compress \
-F "file=@photo.jpg" \
-F "targetMB=0.5" \
--output compressed.webpcurl -X POST http://localhost:3000/api/convert \
-F "file=@photo.heic" \
-F "outputFormat=jpeg" \
--output converted.jpgcurl http://localhost:3000/api/health
# {"ok":true,"version":"1.0.0","env":"production","timestamp":"..."}Full reference: docs/API.md.
Feather reads config from environment variables. The full table is in docs/DEPLOYMENT.md, and a complete .env.example ships in the repo. The most common knobs:
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP port |
BASE_URL |
http://localhost:3000 |
Public URL (used in metadata) |
MAX_UPLOAD_MB |
25 |
Reject uploads larger than this |
MAX_PIXELS |
60000000 |
Reject decoded images with more pixels than this (decode-bomb guard) |
RATE_LIMIT_PER_MINUTE |
60 |
Per-IP rate limit |
LOG_LEVEL |
info |
trace / debug / info / warn / error / fatal |
HUGGINGFACE_TOKEN |
— | Optional Bearer token for the model proxy |
MODEL_CACHE_DIR |
— | Disk path to persist downloaded models |
- API reference — endpoints, parameters, response headers, errors
- Architecture — request flow, sharp pipeline, MODNet worker
- Deployment — Docker, Compose, reverse proxies, scaling
- Self-hosting guide — full self-host playbook + offline models
- Development — local setup, scripts, testing
- Contributing — workflow, conventions
- Node.js ≥ 22 (or Docker)
- pnpm ≥ 10 for development (Corepack handles this)
- ~512 MB RAM for typical workloads; 1 GB recommended for large images / AVIF
MIT — see LICENSE.
Background removal uses the MODNet model via the Xenova/modnet ONNX export.