Set which app opens which file extension, UTI or URL scheme on macOS.
A modern successor to RCDefaultApp, SwiftDefaultApps and duti.
Ships as a macOS app and a CLI (mda). Requires macOS 15+.
- Browse types by family, or by app to see everything one app handles
- Change a handler from the dropdown in each row, or pick any app via "Other…"
- Filter across extensions, UTIs and app names (⌘F)
- Covers every type and URL scheme your installed apps declare
- English, Deutsch, Français, Español, Italiano, Português, Nederlands, Polski, 简体中文
mda get md # default handler for .md
mda ls md # all candidates, default marked *
mda set com.sublimetext.4 md
mda set com.apple.Safari public.html
mda set com.apple.Mail mailto:
mda dump # curated types with handlers (or --json)
mda dump --all # every type your installed apps declare
mda save # snapshot handlers to ~/.mda/default
mda apply # restore the default preset
mda apply work # a named preset (~/.mda/work)
mda apply settings.duti # any duti settings file
mda apply initial # undo: the state before mda touched this mac
mda --versionmd and .md are extensions, public.html is a UTI, mailto: is a URL scheme. mda classifies the target itself.
mda save writes the current associations to ~/.mda/, one plain-text file per preset, duti syntax. Put the folder in your dotfiles. It warns when the folder isn't under git.
mda apply restores a preset. Apps that aren't installed are skipped and listed, and the exit code is non-zero so a bootstrap script can react. Re-run it after installing them.
The app has the same thing under Presets, with a preview before anything is written.
Before mda changes anything for the first time, it records how the machine already looked. Written once, never rewritten.
mda apply initial # put it all backIt isn't a preset and isn't in ~/.mda — it lives in ~/Library/Application Support/mda, because it describes one machine and would be wrong on any other. Keep ~/.mda in your dotfiles; this stays behind. ADR 0002.
mda apply reads them as-is. Three-field lines (bundle-id uti role) work unchanged; the role column is ignored. Two fields mean a URL scheme, like duti -s.
brew tap klabast/tap
brew trust klabast/tap # required for third-party taps
brew install --cask macosdefaultapps # app, with mda bundled in
brew install mda # cli on its ownNeither needs Xcode. The app is also on the latest release page.
Build from source:
swift build -c release # cli: .build/release/mda
scripts/package-app.sh # app: build/macOSDefaultApps.app- The app checks GitHub for a newer release at launch and tells you. It installs nothing;
brew upgradeor the release page does that. - Changing the default browser triggers a macOS consent dialog. It can't be silenced.
- There is no API to remove an association, only to point it somewhere else. LaunchServices clears out stale ones.
- The extension
tsis MPEG-2 Transport Stream system-wide, not TypeScript.
MIT
