exifr
Fast JavaScript EXIF and metadata reader for photos
exifr is a fast and versatile JavaScript library for reading EXIF, IPTC, XMP, GPS, and other metadata from images. It is self-hostable and used as a metadata-parsing component in photo management web apps.
Key features
- Reads EXIF, IPTC, XMP, GPS
- Very fast parsing
- Browser and Node support
- Tiny footprint
Pros & cons
Strengths
- Comprehensive metadata support
- Excellent performance
Trade-offs
- Library, not an app
- Read-only
exifr replaces
Last reviewed Sep 13, 2026 · 786 words
exifr reads the metadata out of a 30 MB RAW or JPEG by fetching only the first few kilobytes, which is why a browser tab can show the capture date, camera model and GPS pin for a whole folder of photos before a single image has finished loading. That is the entire product. It is a JavaScript library with 1,248 GitHub stars, MIT-licensed, that runs in Node and in the browser, and it appears in the photos category because self-hosters building their own gallery, upload form or organiser reach for it. If you want a finished photo server, close this tab and go read about Immich; if you are writing the code yourself, keep reading.
What it parses, and what it refuses to
The library handles EXIF, IPTC, XMP, ICC and GPS segments from JPEG, TIFF, HEIC, AVIF and PNG, plus embedded thumbnails and the orientation flag. Three calls cover most work:
import exifr from 'exifr'
const all = await exifr.parse(file) // every tag it can find
const gps = await exifr.gps(file) // { latitude, longitude }
const rot = await exifr.orientation(file) // 1..8, for CSS rotation
file can be a path, a URL, a Buffer, a Blob from an <input type="file">, or an ArrayBuffer. What it will not do is write. There is no exifr.set(), so stripping location data before sharing or fixing a wrong timezone needs ExifTool or a write-capable library; ExifCleaner is the desktop tool for the strip-before-sharing case. It also does not decode the image, so pairing it with sharp or the browser's own decoder is the normal arrangement.
Why it is fast, and the trade you make for that
Most metadata readers pull the whole file into memory. exifr issues a ranged read for the first 64 KB, finds the APP1 segment, and stops; for a folder of 2,000 phone photos over a slow NAS mount, that is the difference between a listing that appears in under a second and one that takes a minute. The trade is that maker notes and deeply nested XMP in unusual files may sit beyond the chunk it reads, and you then either raise chunkSize in the options or accept partial results. The published bundles reflect the same trade: full for everything, lite for EXIF plus GPS, and mini at a few kilobytes for orientation and dates only, which is the one I ship to browsers.
Where it sits in a self-hosted photo stack
The big self-hosted galleries do not use it. Immich and PhotoPrism shell out to ExifTool or use Go and Java readers, because they need the long tail of RAW formats and writeback. exifr belongs in three smaller places. First, upload forms: read the date and GPS client-side before the bytes leave the browser, so the server can reject duplicates or sort into folders without a second pass. Second, static galleries: a build script in Node that walks a directory, calls exifr.parse, and emits JSON for a gallery generator. Third, small Express or Fastify services that answer "when and where was this taken" for a Nextcloud or Syncthing folder without installing a 100 MB Perl dependency. Each is a self-hosted thing; none of them is a self-hosted app.
The privacy reason a self-hoster cares about EXIF at all
Every photo from a phone carries a GPS fix accurate to about 5 metres, the device model, and often the owner's name in the XMP creator field. If you run a public gallery or a family sharing page, reading metadata on upload is how you decide what to keep. A pattern that works: read with exifr on upload, store the coordinates in your own database for the map view, then re-encode the served image without metadata so the public file carries nothing. exifr gives you the first step in 3 lines; the strip step needs sharp's withMetadata() defaults or ExifTool. The Google Photos exit guide explains why keeping this data private matters once photos leave a walled garden.
What I'd do
Use exifr in any Node or browser code where you read metadata and never write it, ship the mini bundle client-side and the full build server-side, and set a fallback to ExifTool for RAW files that return empty results. Do not build a gallery around it when Immich exists; the photos category has the finished apps. And if you are deciding between exifr and a commercial metadata API, the choice is not close: one dependency, zero network calls, 64 KB per file, and the coordinates never leave your machine.
Similar photo management apps
Immich
Photo ManagementHigh-performance self-hosted photo and video backup
Replaces Google Photos, iCloud Photos
PhotoPrism
Photo ManagementAI-powered photo app for the decentralized web
Replaces Google Photos
Ente Photos
Photo ManagementEnd-to-end encrypted photo storage and backup
Replaces Google Photos, iCloud Photos
DeepFace
Photo ManagementFace recognition and facial attribute analysis framework
Replaces AWS Rekognition, Azure Face API
gallery-dl
Photo ManagementCommand-line tool to download image galleries from websites
Replaces Manual downloads
Color Thief
Photo ManagementLibrary to extract color palettes from photos
Replaces Commercial color analysis APIs