A native macOS menu-bar app for managing /etc/hosts through switchable profiles.
→ Download page — always points at the latest release.
Requires macOS 26 (Tahoe) or later. Unsigned — no Apple Developer Program needed.
- Profiles — create, edit, and instantly switch named
/etc/hostsconfigurations from the menu bar. - Blocklist sources — subscribe to hosts-format lists. Built in: StevenBlack (Unified, plus Fake News / Gambling / Porn / Social) and HaGeZi (Light → Normal → Pro → Pro++ → Ultimate). Sources auto-refresh with conditional-GET (ETag) caching, and you can add your own.
- Fragments — reusable hosts snippets you toggle into any profile (e.g. a "Docker" fragment listing your local container hostnames, switched on only in your Dev profile). A draft-based editor lets you save changes without a password prompt; you re-apply once when you're ready.
- Stale-aware apply — profiles, fragments, and sources show a "needs re-apply" badge when your edits differ from what's live in
/etc/hosts, and each editor has Cancel to revert unapplied changes back to the applied state. - Drag-to-reorder — reorder profiles, sources, and fragments directly in the sidebars.
- Import / export — back up your whole setup to a JSON file, restore it on another machine, or import a plain hosts file as a profile or fragment.
- Launch at login & updates — runs quietly as a menu-bar-only app (no Dock icon), can optionally show the active profile name next to the menu-bar icon, and checks GitHub Releases for new versions — installing them in place and relaunching, no drag-and-drop.
The app is unsigned (it deliberately uses no Apple Developer Program, signing, or privileged helper), so macOS blocks it on first launch. To allow it:
- Double-click Hosts Switchr; when macOS warns it "can't verify the developer," click Done (not "Move to Trash").
- Open System Settings → Privacy & Security and scroll to the Security section.
- Click Open Anyway next to "Hosts Switchr" was blocked to protect your Mac, then authenticate and click Open.
macOS only asks once — after that it launches normally.
If you don't have a prebuilt app, build it from source — see For developers.
- Launch the app — it lives in the menu bar (no Dock icon).
- Profiles — select a profile and click Apply to write it to
/etc/hosts. You'll be asked for your admin password; this is the only privileged step. Switch the active profile anytime straight from the menu-bar menu. - Sources — toggle built-in or custom blocklists on per profile. Right-click a source to refresh it, or use Refresh All Sources in the menu bar.
- Fragments — create reusable snippets and toggle them into any profile.
- Settings — enable Launch at login and the active-profile name in the menu bar.
- Rename & delete — new profiles and fragments open ready to rename; press ⌘⌫ (or right-click → Delete) to remove the selected item. The active profile and built-in sources can't be deleted.
New to it? See Help → Hosts Switchr Help for a built-in guide.
Your data lives in ~/Library/Application Support/HostsSwitchr/. /etc/hosts is only ever changed when you click Apply.
- macOS 26 (Tahoe)+, Xcode 26+
- xcodegen (
brew install xcodegen) - SwiftLint (
brew install swiftlint) — enforced in the build phase
# Logic package (no Xcode needed)
cd HostsKit && swift test
# App — generate the project, then open or build
cd App && xcodegen && open HostsSwitchr.xcodeprojHeadless build:
cd App && xcodegen && xcodebuild \
-project HostsSwitchr.xcodeproj \
-scheme HostsSwitchr \
-destination 'platform=macOS' \
build
App/HostsSwitchr.xcodeprojis generated by xcodegen and git-ignored — editApp/project.yml, not the project file. Run SwiftLint from the repo root.
./scripts/make-dmg.shBuilds the Release configuration and produces dist/HostsSwitchr-<version>.dmg, a drag-to-Applications disk image. The version comes from MARKETING_VERSION in App/project.yml. Requires create-dmg (brew install create-dmg).
hosts-switchr/
├── HostsKit/ # Pure Swift package — all logic, zero UI, zero app framework
│ └── Sources/HostsKit/
│ ├── Profile, ProfileStore # named /etc/hosts configs, ordered, persisted
│ ├── LocalFragment, FragmentStore # reusable local snippets
│ ├── RemoteSource, SourceCatalog # blocklist subscriptions + built-in catalog
│ ├── SourceFetcher, SourceRefresher # conditional-GET fetch + scheduling
│ ├── MergedHostsComposer # streams local → fragments → sources to a temp file
│ ├── HostsApplier, PrivilegedRunner # atomic privileged write to /etc/hosts via osascript
│ ├── ConfigBundle # import/export bundle model
│ └── …validation, scanning, login-item protocol
└── App/ # SwiftUI macOS app — thin UI layer over HostsKit
└── Sources/
├── HostsSwitchrApp # @main, MenuBarExtra, Window, Settings scenes
├── AppModel # @Observable coordinator; owns all stores
└── …views
Key invariants:
- All persistent state lives in
~/Library/Application Support/HostsSwitchr/. - Writes to
/etc/hostsgo through a unique-named temp file →cpviaosascript(no helper daemon, no signing required); the merged content is never interpolated into the shell command. - Remote sources require
https://; imported URLs go through the sameSourceURLPolicyguard. - Fail-closed everywhere: corrupt store files are preserved to a
.corruptpath before any overwrite.
For the full agent/contributor guide (conventions, security invariants, build/test workflow), see AGENTS.md.
MIT