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

mdfind-node

v1.4.0

Published

Node.js bindings for macOS Spotlight search (mdfind, mdls, mdutil)

Readme

mdfind-node 🔍

Supercharged macOS file and metadata search using mdfind for Node.js! ✨

npm version License: ISC Lint

A powerful Node.js wrapper for macOS's Spotlight search (mdfind), bringing system-level search capabilities to your JavaScript applications.

✨ Features

  • 🚀 Full Spotlight Integration - Access all macOS Spotlight search capabilities
  • 🔄 Smart Query Builder - Type-safe, fluent API for building complex searches
  • 🔄 Live Search Support - Real-time file monitoring and updates
  • 📦 Batch Operations - Run multiple searches in parallel or sequence
  • 📝 Rich Metadata - Access EXIF, XMP, and system metadata
  • 💪 Type-Safe - Full TypeScript support with detailed types
  • 🛠️ Configurable - Extensive options for fine-tuned control
  • 🌳 Type Trees - Support for content type hierarchies
  • 🎨 Specialized Methods - Purpose-built methods for common file types

📥 Documentation

📥 Installation

# Using pnpm (recommended)
pnpm add mdfind-node

# Using npm
npm install mdfind-node

# Using yarn
yarn add mdfind-node

# Using bun
bun add mdfind-node

🚀 Quick Start

import { QueryBuilder } from 'mdfind-node'

// Find recent Markdown files
const docs = await new QueryBuilder()
  .isMarkdown()
  .modifiedAfter(new Date('2024-01-01'))
  .inDirectory('~/Documents')
  .execute()

// Find high-resolution photos
const photos = await new QueryBuilder()
  .contentType('public.image')
  .minImageDimensions(3000, 2000)
  .hasGPS()
  .inDirectory('~/Pictures')
  .execute()

// Find large media files
const videos = await new QueryBuilder()
  .isAudiovisual()
  .largerThan(100 * 1024 * 1024) // > 100MB
  .inDirectory('~/Movies')
  .execute()

🎯 Key Features

🔍 Smart Query Builder

The QueryBuilder provides a fluent, type-safe API for building complex searches:

import { QueryBuilder } from 'mdfind-node'

// Find documents by author
const authorDocs = await new QueryBuilder()
  .contentType('com.adobe.pdf')
  .author('John Doe')
  .createdAfter(new Date('2024-01-01'))
  .inDirectory('~/Documents')
  .execute()

// Find photos from a specific camera
const cameraPhotos = await new QueryBuilder()
  .contentType('public.image')
  .takenWith('iPhone 14 Pro')
  .hasGPS()
  .inDirectory('~/Pictures')
  .execute()

// Find code files with specific content
const codeFiles = await new QueryBuilder()
  .isText()
  .extension('ts')
  .containing('QueryBuilder')
  .modifiedAfter(new Date('2024-01-01'))
  .execute()

// Combine conditions with OR
const mediaFiles = await new QueryBuilder()
  .useOperator('||')
  .extension('mp4')
  .extension('mov')
  .extension('avi')
  .largerThan(50 * 1024 * 1024)
  .execute()

🔄 Live Search

import { QueryBuilder, mdfindLive } from 'mdfind-node'

// Create a query to watch for new PDFs
const query = new QueryBuilder().isPDF().inDirectory('~/Downloads').toString()

const search = mdfindLive(
  query,
  { reprint: true },
  {
    onResult: paths => console.log('New matches:', paths),
    onError: error => console.error('Search error:', error),
    onEnd: () => console.log('Search ended')
  }
)

📦 Batch Operations

import { QueryBuilder } from 'mdfind-node'
import { batchSearch } from 'mdfind-node'

// Create multiple queries
const searches = [
  {
    query: new QueryBuilder().contentType('public.image').minImageDimensions(1920, 1080).toString(),
    options: { onlyInDirectory: '~/Pictures' }
  },
  {
    query: new QueryBuilder()
      .contentType('com.adobe.pdf')
      .modifiedAfter(new Date('2024-01-01'))
      .toString(),
    options: { onlyInDirectory: '~/Documents' }
  }
]

// Run them in parallel
const results = await batchSearch(searches)

// Or use utility functions for common patterns
import { mdfindMultiDirectory, mdfindMultiQuery } from 'mdfind-node'

// Search same query across multiple directories
const directoryResults = await mdfindMultiDirectory(
  new QueryBuilder().contentType('public.image').toString(),
  ['~/Pictures', '~/Documents']
)

// Search multiple queries in one directory
const queryResults = await mdfindMultiQuery(
  [
    new QueryBuilder().contentType('public.image').toString(),
    new QueryBuilder().contentType('com.adobe.pdf').toString()
  ],
  '~/Documents'
)

📝 Extended Metadata

import { getExtendedMetadata } from 'mdfind-node'

const metadata = await getExtendedMetadata('photo.jpg')
console.log('Basic:', metadata.basic)
console.log('EXIF:', metadata.exif)
console.log('XMP:', metadata.xmp)

🎯 Specialized Search Methods

The QueryBuilder includes specialized methods for common file types:

import { QueryBuilder } from 'mdfind-node'

// Find text files
const textFiles = await new QueryBuilder().isText().modifiedAfter(new Date('2024-01-01')).execute()

// Find media files
const mediaFiles = await new QueryBuilder()
  .isAudiovisual()
  .largerThan(10 * 1024 * 1024)
  .execute()

// Find applications
const apps = await new QueryBuilder().isApplication().inDirectory('/Applications').execute()

// Find configuration files
const configs = await new QueryBuilder().isPlist().inDirectory('~/Library/Preferences').execute()

// Find development files
const devFiles = await new QueryBuilder()
  .useOperator('||')
  .isText()
  .isMarkdown()
  .isJSON()
  .isYAML()
  .inDirectory(process.cwd())
  .execute()

🔍 Attribute Discovery

Spotlight attributes can be complex to work with. This library provides utilities to help you discover and understand available attributes:

import { discoverAttributes, searchAttributes, getContentTypes } from 'mdfind-node'

// Get all available attributes for a specific file
const fileAttributes = discoverAttributes('path/to/file.jpg')

// Search for attributes by keyword
const imageAttrs = searchAttributes('image')
console.log(imageAttrs)
// [
//   {
//     name: 'kMDItemPixelHeight',
//     description: 'Height of the image in pixels',
//     type: 'number',
//     example: 1080,
//     category: 'image'
//   },
//   ...
// ]

// Get all known content types
const contentTypes = getContentTypes()
console.log(contentTypes['public.image']) // 'Image files (JPEG, PNG, etc.)'

// Get attributes by category
const locationAttrs = getAttributesByCategory('location')

Content Type Trees

Files in macOS are organized in a type hierarchy. For example:

public.item
└── public.content
    ├── public.text
    │   ├── public.plain-text
    │   └── net.daringfireball.markdown
    └── public.audiovisual-content
        ├── public.audio
        └── public.movie

Common Content Types

Basic Types:

  • public.item - Base type for all items
  • public.content - Base type for all content
  • public.text - Text-based content
  • public.composite-content - Content with multiple parts

Documents:

  • public.plain-text - Plain text files
  • public.rtf - Rich Text Format documents
  • com.adobe.pdf - Adobe PDF Document
  • net.daringfireball.markdown - Markdown Document

Media:

  • public.image - Image files (JPEG, PNG, etc.)
  • public.audio - Audio files (MP3, WAV, etc.)
  • public.movie - Video files (MP4, MOV, etc.)
  • public.audiovisual-content - Audio/Visual content

Code:

  • public.source-code - Source Code File
  • public.shell-script - Shell Script
  • public.json - JSON File
  • public.yaml - YAML File

System:

  • com.apple.bundle - Generic Bundle
  • com.apple.application - Generic Application
  • com.apple.property-list - Property List (plist)

Common Attributes

  • kMDItemContentType - The type of content
  • kMDItemContentTypeTree - The content type hierarchy
  • kMDItemDisplayName - The display name of the file
  • kMDItemFSName - The filename on disk
  • kMDItemContentCreationDate - When the file was created
  • kMDItemContentModificationDate - When the file was last modified
  • kMDItemPixelHeight - Height of the image in pixels
  • kMDItemPixelWidth - Width of the image in pixels
  • kMDItemLatitude - GPS latitude where photo/video was taken
  • kMDItemLongitude - GPS longitude where photo/video was taken

👩‍💻 Development

# Install dependencies
pnpm install

# Development build with watch mode
pnpm dev

# Production build
pnpm build

# Run tests
pnpm test

# Run examples
pnpm examples:basic
pnpm examples:advanced
pnpm examples:query-builder
pnpm examples:live-search
pnpm examples:metadata
pnpm examples:batch
pnpm examples:discover
pnpm examples:content-types

📄 License

ISC © Matthew Herod