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

@tepungpelita/directus-exif-extension

v0.2.0

Published

Import files with EXIF metadata and manage them in Directus.

Readme

This Directus extension reads the EXIF metadata of every image you upload, stores it next to the file in an exif_metadata collection, and adds an EXIF module to the admin where you can browse, search and inspect it.

  • Automatic. Upload or replace an image and its EXIF is stored. Nothing to configure.
  • An EXIF module in the admin. An image list with thumbnails, a details drawer with every tag, search and a folder filter.
  • Queryable from your code. One regular collection, linked one-to-one with directus_files.

Using the EXIF module

Turn the module on once: Settings → Settings → Module Bar, switch EXIF on and save. Directus does not add new modules to a module bar you have already customized.

1. Images

Choose EXIF in the module bar, then Images in the sidebar. You see one row per image, newest first: thumbnail, file name and size, camera and lens, date and time taken, the main exposure settings, and a pin if the image has GPS.

2. Click an image for everything we know about it

A drawer opens with the exposure readout (aperture, shutter, ISO, focal length), camera body, lens and date taken, the GPS position with a link to OpenStreetMap, and every stored tag with a filter box. Open image, File library and Download JSON sit above the readout. Press Esc to close it.

3. Find images

  • Search matches the camera make, camera model, lens, file name and title, ignoring case.
  • Folder narrows the list to a file library folder, including its subfolders.

Both filters work across every page of results.

4. Export

  • Download JSON (in the drawer) saves one image with all its tags.
  • For many images at once, use Directus's own export: Content → Exif Metadata → Import / Export.

Exports contain GPS coordinates when an image has them. Treat them like the images themselves.

5. About

About in the sidebar shows the version, who made the extension and where the source lives.

Who can see it

The EXIF entry is shown only to administrators and to roles that can read exif_metadata. Those roles also need Read on directus_files and directus_folders; without them the page shows a "No access" message.

How it works

The bundle contains a hook, exif-import (src/hooks/exif-import), and the EXIF module (src/modules/exif). The hook does the work:

  1. Provisioning — on app.after it creates the exif_metadata collection and its relation to directus_files if they don't exist (definition in schemas/exif-metadata.ts).
  2. Import — on files.upload it reads the uploaded image from disk, parses it with exifr, and creates or updates the exif_metadata row for that file.

Only JPEG, PNG, TIFF, HEIC and AVIF images are read (exifr can't parse WebP or GIF); other files and images without EXIF data are skipped. Errors are logged and never block the upload.

The module only reads the collection through the normal Directus items API, so it follows your roles and permissions and needs no extra server code.

Collection: exif_metadata

| Field | Type | Source EXIF tag | | ------------------------------------------- | -------------------------------------------------------- | ---------------------------------------- | | file | uuid (m2o → directus_files, unique, cascade on delete) | — | | camera_make, camera_model, lens_model | string | Make, Model, LensModel | | date_taken | timestamp | DateTimeOriginal / CreateDate | | orientation | integer | Orientation | | iso | integer | ISO | | focal_length, aperture, exposure_time | decimal | FocalLength, FNumber, ExposureTime | | gps_latitude, gps_longitude | decimal | GPS (decimal degrees) | | gps_altitude | decimal | GPSAltitude | | raw | json | Full parsed EXIF payload |

The collection is created automatically by the hook on startup; no migration is needed.

Querying via the API

exif_metadata is a regular collection, so use the standard items endpoints. The authenticated role needs read permission on exif_metadata.

# EXIF for one file
curl -H "Authorization: Bearer $TOKEN" \
  "$DIRECTUS_URL/items/exif_metadata?filter[file][_eq]=<file-id>&limit=1"

# Images taken with a given camera, newest first, with the related file info
curl -H "Authorization: Bearer $TOKEN" \
  "$DIRECTUS_URL/items/exif_metadata?filter[camera_make][_eq]=Canon&sort=-date_taken&fields=id,camera_model,date_taken,file.id,file.filename_download"

# Only images that have GPS coordinates
curl -H "Authorization: Bearer $TOKEN" \
  "$DIRECTUS_URL/items/exif_metadata?filter[gps_latitude][_nnull]=true&fields=file,gps_latitude,gps_longitude"

With the SDK:

import { createDirectus, rest, readItems } from '@directus/sdk'

const client = createDirectus(DIRECTUS_URL).with(rest())
const items = await client.request(
  readItems('exif_metadata', { filter: { file: { _eq: fileId } }, limit: 1 }),
)

Installation

Search for Directus Exif Extension in the Directus Marketplace (Settings → Marketplace), or install from npm:

npm install @tepungpelita/directus-exif-extension

This hook reads files from disk and uses Directus services, so it is not a sandboxed extension. On self-hosted instances, set MARKETPLACE_TRUST=all (or trust this package) to install it from the Marketplace.

Requirements

  • Directus >=11.0.0 (developed and tested on 12; the module's styling uses the theme variables introduced in 11)
  • Files stored on the local storage driver (the default). The hook reads the file from the location's STORAGE_<LOCATION>_ROOT (default ./uploads); files on other drivers are skipped with a warning.

Development

From the repo root:

pnpm --filter @tepungpelita/directus-exif-extension build   # or: pnpm build
pnpm docker:restart:directus

Upload a JPEG with EXIF data in the Directus file library, then open EXIF in the module bar (see above to turn it on).

The shared formatting helpers live in the private packages/exif-ui-core workspace package and are bundled into the build.