How to Configure Default Applications on Mac Using the duti Command-Line Utility

Setting up a new Mac or provisioning developer workstations often involves changing dozens of default application handlers. By default, macOS opens source code files, plain text documents, markdown notes, and video media in Apple’s built-in utilities like TextEdit and QuickTime Player rather than modern development tools like Visual Studio Code, Cursor, or VLC. While macOS lets you manually change default handlers via Finder’s “Get Info” pane, repeating this process for every file extension (.js, .ts, .py, .md, .json) is tedious. The open-source duti command-line utility enables complete automation of default application associations via shell scripts and configuration files.

What Is duti and How Does It Function?

The duti utility (Default Uniform Type Identifier) interfaces directly with the macOS Launch Services framework. Key characteristics include:

  • UTI and Extension Mapping: Can set default applications based on standard file extensions (such as .pdf or .html) or Apple Uniform Type Identifiers (UTIs like public.plain-text or public.json).
  • Bundle Identifier Association: Uses reverse-DNS application bundle IDs (e.g. com.microsoft.VSCode) to link target applications unambiguously.
  • URL Protocol Scheme Handling: Sets default handlers for custom web protocols like mailto:, http:, ssh:, and ftp:.
  • Scriptable Provisioning: Allows you to store your default application settings in a simple text configuration file for automated dotfile installations.

Step 1: Install duti on macOS

The most straightforward method to install duti is via Homebrew:

brew install duti

Verify that the binary is installed and operational:

duti -V

Step 2: Find Application Bundle Identifiers

To assign an application using duti, you must identify its unique macOS bundle identifier. Run osascript or mdls to query installed applications:

Find Bundle ID via AppleScript

# Find bundle ID for Visual Studio Code
osascript -e 'id of app "Visual Studio Code"'
# Returns: com.microsoft.VSCode

# Find bundle ID for VLC Player
osascript -e 'id of app "VLC"'
# Returns: org.videolan.vlc

# Find bundle ID for Google Chrome
osascript -e 'id of app "Google Chrome"'
# Returns: com.google.Chrome

Step 3: Find Uniform Type Identifiers (UTIs) for File Types

To determine the exact UTI assigned to a specific file on your system, use the native mdls (Metadata List) command:

mdls -name kMDItemContentType -name kMDItemContentTypeTree script.py

Terminal output will display the primary content type (e.g. public.python-script) and its parent hierarchy.

Step 4: Associate File Extensions and UTIs with duti

The duti syntax follows a clear structure: duti -s <bundle_id> <extension_or_uti> <role>.

The role parameter defines application permissions:

  • all: Default application for opening, viewing, and editing.
  • editor: Opens file for editing.
  • viewer: Opens file strictly for reading/viewing.

Set Default Editor for Programming Extensions

# Set Visual Studio Code as default handler for code and text files
duti -s com.microsoft.VSCode .js all
duti -s com.microsoft.VSCode .ts all
duti -s com.microsoft.VSCode .py all
duti -s com.microsoft.VSCode .json all
duti -s com.microsoft.VSCode .md all
duti -s com.microsoft.VSCode .yaml all

Set Default Video Player

# Set VLC as default player for video files
duti -s org.videolan.vlc .mkv all
duti -s org.videolan.vlc .mp4 all
duti -s org.videolan.vlc .avi all

Set Default URL Protocol Handlers

# Set Google Chrome as default handler for web URLs
duti -s com.google.Chrome http
duti -s com.google.Chrome https

Step 5: Inspect Current Default Handlers

To check which application currently handles a particular extension or UTI:

# Check default handler for .py files
duti -x py

# Check default handler for a UTI
duti -d public.plain-text

The output reports the application name, bundle identifier, and full filesystem path.

Step 6: Automate Workstation Provisioning via a duti Configuration File

Rather than executing individual commands, save all your desired associations into a unified configuration file (e.g. ~/.duti):

# ~/.duti configuration template
# bundle_id          uti_or_extension    role

com.microsoft.VSCode  .c                  all
com.microsoft.VSCode  .cpp                all
com.microsoft.VSCode  .go                 all
com.microsoft.VSCode  .rs                 all
com.microsoft.VSCode  public.plain-text   all
com.microsoft.VSCode  public.json         all

org.videolan.vlc      .mp4                viewer
org.videolan.vlc      .mkv                viewer
org.videolan.vlc      public.movie        viewer

To apply all mappings across your operating system in one step, point duti to the configuration file:

duti ~/.duti

Launch Services updates immediately; no restart or Finder reload is required.

Resetting Launch Services Cache

If macOS occasionally fails to register a new handler after a major operating system update, rebuild the Launch Services database using the native lsregister tool:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user
killall Finder

After the cache rebuilds, re-run duti ~/.duti to re-establish your preferred application handlers.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.