A native macOS menu bar app for monitoring temperatures and controlling fan speeds on Apple Silicon Macs.
- Real-time monitoring — Reads 400+ SMC temperature sensors and fan RPM directly, no kernel extensions required
- Menu bar integration — Lives in the menu bar with a compact status dropdown; Dock icon only appears when the dashboard is open
- Manual fan control — Set custom RPM, full speed, or auto per fan via a privileged helper daemon
- Temperature-based profiles — Create named profiles with rules like "if sensor X reaches Y degrees, set fan Z to W rpm"
- Hysteresis with 3°C deadband prevents rapid toggling
- Highest RPM wins when multiple rules target the same fan
- Fans return to auto when no rules trigger
- Safe by design
- Read-only monitoring requires no privileges
- Fan writes go through a separate privileged helper with a 10-second watchdog — if the app crashes, fans revert to auto
- RPM values are double-clamped (evaluator + helper)
- Taking fan control is an explicit, acknowledged action
- macOS 14.0 (Sonoma) or later
- Apple Silicon Mac (M1 / M2 / M3 / M4 / M5 series)
- Download
MacFanControl-vX.X.X.zipfrom Releases - Unzip and move
MacFanControl.appto/Applications/ - Launch the app (right-click → Open on first launch since it's ad-hoc signed)
- Click "Install helper" in the status bar when prompted — this installs the privileged daemon needed for fan control
Temperature monitoring works immediately. Fan control becomes available after the helper is installed.
Requires the Swift toolchain (/usr/bin/swift), no Xcode needed.
bash scripts/build.shThe app bundle is assembled at build/MacFanControl.app.
Helper install/uninstall scripts are available in scripts/ for development, but normal users don't need them — the app handles installation via its UI.
- Monitor — The dashboard shows all detected temperature sensors and fan speeds. No privileges needed.
- Take fan control — Click "Take fan control..." in the dashboard or menu bar. This activates the privileged helper.
- Manual control — Use the slider to set a custom RPM, or click "Full speed" / "Auto" per fan.
- Profiles — Create temperature-based profiles that automatically adjust fan speeds:
- Select a profile from the dropdown in the Fans panel or the menu bar "Profiles" submenu
- Each rule maps a sensor threshold to a target RPM for a specific fan
- Profiles are persisted to
~/Library/Application Support/MacFanControl/profiles.json
┌─────────────────────┐ ┌──────────────────────────┐
│ MacFanControlApp │ │ MacFanControlHelper │
│ (SwiftUI GUI) │────▶│ (launchd root daemon) │
│ │ XPC │ │
│ • SMC reads (user) │ │ • SMC writes (root) │
│ • Profile engine │ │ • 300ms reconciliation │
│ • Menu bar extra │ │ • 10s watchdog │
└─────────────────────┘ └──────────────────────────┘
│ │
└──────────┬───────────────────┘
▼
┌──────────────┐
│ AppleSMC │
│ (IOKit) │
└──────────────┘
- MacFanControlCore — Shared library: SMC access (via C shim), fan/sensor readers, protocol definitions, profile evaluator
- MacFanControlApp — SwiftUI app with menu bar extra, dashboard, profile editor
- MacFanControlHelper — Privileged launchd daemon for fan writes, communicates via
NSXPCConnection - SMCShim — Minimal C target wrapping IOKit's
SMCKeyData_tstruct
On M-series Macs, the SMC driver has specific behaviors:
- Fan RPM keys use
flttype (IEEE 754 float), not thefpe2format from Intel Macs - Writing
F0md=1(manual mode) triggers a session-scoped latch — auto-mode reads become degraded until reboot thermalmonitordclobbersF0Tgevery ~1.4 seconds, so the helper uses a 300ms reconciliation loop to maintain custom targets- Reads work as a normal user; writes require root
MIT