Change the default macOS app for developer file types (.json, .md, .py, .sh, .yaml, .xml, .js, …) from the command line. One small, dependency-free Swift script that stops Xcode from hijacking every source file and hands them to Cursor, VS Code, Zed, Sublime Text, or any editor you choose.
No sudo. No Homebrew. No duti. Fully reversible.
swift set-default-editor.swift cursorOn macOS, every file type has a default application resolved through a system database called Launch Services. When you install Xcode, it registers itself as the owner (the highest Launch Services rank) of the entire public.source-code family — and of dozens of individual developer types: public.json, net.daringfireball.markdown, public.python-script, public.yaml, public.xml, public.shell-script, and more.
Other editors (Cursor, VS Code, TextEdit, Chrome…) also claim those types, but only at a lower rank (Alternate / Viewer). When there is no explicit user choice, Launch Services returns the highest-ranked handler — which is Xcode.
Double-click file.json
│
▼
┌─────────────────────┐
│ Launch Services │ resolves the UTI (public.json) and
│ ranks candidates │ returns the highest-ranked handler
└─────────┬───────────┘
│
user override? ── NO ──► 1. Xcode (rank: Owner) ◄── wins
│ 2. Cursor (rank: Alternate)
YES 3. VS Code / TextEdit / Chrome …
│
▼
the app YOU picked
That is why .txt escapes Xcode (TextEdit owns public.plain-text) but .json, .py, .md, .yaml, .sh don't — no other app is set as their explicit default. This script writes that missing override.
This script calls the official Launch Services API
LSSetDefaultRoleHandlerForContentType
to set your chosen editor as the explicit default for a curated list of developer file types. An explicit user override always beats Xcode's Owner rank.
# Set your editor as default for all developer file types
swift set-default-editor.swift cursor
swift set-default-editor.swift vscode
swift set-default-editor.swift zed
# Also take over plain-text .txt files (left to TextEdit by default)
swift set-default-editor.swift cursor --include-txt
# Preview the changes without applying anything
swift set-default-editor.swift vscode --dry-run
# Inspect the current default handler for each type
swift set-default-editor.swift --list
# Revert everything back to Xcode
swift set-default-editor.swift xcodecursor · vscode (code) · vscodium · zed · sublime (sublime3) · nova · bbedit · textmate · xcode · textedit
You can also pass a raw bundle id (com.microsoft.VSCode) or a path to a .app — so any editor works, even if it has no shortcut.
public.source-code (and its whole family), public.json, Markdown, public.yaml, public.xml,
shell / bash / zsh / csh / ksh / tcsh scripts, C / C++ / Objective-C sources and headers, Swift,
Ruby, Perl, PHP, Make, JavaScript, assembly / NASM, and generic scripts.
.txt is intentionally left to TextEdit unless you pass --include-txt.
- macOS (tested on Sonoma / Sequoia)
- Swift toolchain — already present if you have the Xcode Command Line Tools (
xcode-select --install)
Run the script with xcode to restore Xcode as the default, or do it manually in Finder:
right-click a file → Get Info → Open with → choose an app → Change All…
- Launch Services keeps a per-user database of file-type → application handlers.
- Each handler has a role (
Editor/Viewer/Shell/All) and a rank (Owner>Default>Alternate>None). - Apps declare the types they handle and their rank via
CFBundleDocumentTypesandUTExportedTypeDeclarationsin theirInfo.plist. - With no user override, the resolver returns the highest-ranked candidate for the file's UTI.
LSSetDefaultRoleHandlerForContentTypewrites a user override that outranks everything — this is exactly what the Finder "Change All…" button does, but scriptable and in bulk.
Inspect the raw database at any time:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Support/lsregister -dumpKeywords: macOS default app for file type, files open in Xcode, change default text editor macOS terminal, set default application command line, Launch Services default handler, LSSetDefaultRoleHandlerForContentType, duti alternative, open .json with VS Code, stop Xcode opening files, Cursor default editor macOS, UTI file association macOS.