Free, open-source fan control for Apple Silicon Macs. Menu bar app + CLI.
Built in 2026 with Swift. No subscriptions, no telemetry, no ads.
Tools like Macs Fan Control and TG Pro charge $15–$20 for fan control that hasn't fundamentally improved in years. Both require manual configuration, neither learns anything about your machine, and both have documented problems on Apple Silicon.
| Feature | ThermalForge | Macs Fan Control | TG Pro |
|---|---|---|---|
| Smart adaptive fan curve | Yes | No | No |
| Machine-specific calibration | Yes | No | No |
| Multi-sensor safety | Yes — all sensors | One sensor per fan | Manual rules only |
| Proactive cooling (ramps before throttle) | Yes | No | No |
| Fan curve type | Graduated continuous | Linear between 2 points | Manual step-function |
| Real-time temp monitoring | Yes | Yes | Yes |
| Menu bar app | Yes | Yes | Yes |
| CLI access | Yes | No | No |
| Thermal data logging (CSV) | Yes | No | Yes |
| Process correlation in logs | Yes | No | No |
| Sleep/wake re-apply | Yes | Yes | Yes |
| Safety override (95°C) | Yes — always active | No | Requires manual setup |
| Crash recovery (heartbeat watchdog) | Yes | Reverts on quit only | Override removes macOS safety |
| Open source | Yes | No | No |
| Price | Free | $15 | $20 |
Macs Fan Control monitors only one temperature sensor per fan. Users have reported GPU overheating while monitoring CPU only, leading to system lockups. Fan control is broken on M3/M4 Pro and Max due to Apple firmware changes.
TG Pro offers more flexibility but requires users to manually configure step-function rules for each fan speed threshold. Its "Override System" mode removes macOS thermal safety entirely — if your rules are wrong, there's no backstop. No learning, no adaptation, no calibration.
AlDente Pro ($30) is a battery management tool with no fan control features. It monitors battery temperature and pauses charging — it does not control fans.
- Real-time CPU, GPU, RAM, SSD, and ambient temperatures in the menu bar
- Five fan profiles with proportional curves (not binary on/off)
- Thermal logging — CSV + JSON data export with process correlation for research
- Automatic fan re-apply after sleep/wake
- Fahrenheit / Celsius toggle
- Safety override: forces max fans if any sensor hits 95°C
- Crash recovery: heartbeat watchdog resets fans if app dies
- Temperature anomaly detection: logs instant spikes (>5°C in 2s) and sustained changes (>10°C in 30s) with process capture
- Privileged daemon — one-time sudo, zero password prompts after
- Native Swift — lightweight, no Electron, no bloat
Every profile uses a proportional curve — fans ramp gradually with temperature, not as binary switches. Ramp rates match Apple's hardware behavior (~400 RPM/sec up, ~200 RPM/sec down) to minimize fan bearing wear. Once fans are on, they stay on until temperature is clearly stable below the threshold (at least 5°C hysteresis) to avoid damaging start/stop cycling.
| Profile | Fans off below | Fans ramp from | Max fan speed | Target |
|---|---|---|---|---|
| Silent | Always off | N/A — hands-off | Apple default | Monitoring only. Lets Apple handle fans. |
| Balanced | 50°C | 60–70°C | 60% | Good balance of noise and cooling for everyday use. |
| Performance | 45°C | 50–65°C | 85% | For sustained workloads where cooling matters more than noise. |
| Max | Never | Always on | 100% | Full cooling, maximum noise. |
| Smart | 55°C | 60–85°C | 100% (adapts) | Proactive curve with rate-of-change awareness. Uses calibration data when available. |
How the curves work: Between the ramp start and target ceiling temperatures, fan speed scales proportionally. At 65°C on Balanced (midpoint of 60–70°C range), fans run at 30% of max RPM. At the ceiling they reach the profile's max. Below the off threshold, fans stop completely. In the gap between off and ramp start (hysteresis zone), fans maintain their current state — if already running they stay at minimum, if already off they stay off.
brew install ProducerGuy/tap/thermalforge
sudo thermalforge installThe first command installs the CLI and the menu bar app to /Applications. The second sets up a background daemon so the app can control fans without needing sudo every time. You only run it once.
git clone https://github.com/ProducerGuy/ThermalForge.git
cd ThermalForge
./setup.shBuilds everything, installs the CLI, creates the menu bar app in /Applications, and sets up the daemon. One password prompt, fully automatic.
Open ThermalForge from Spotlight, Finder (Applications > ThermalForge), or terminal:
open /Applications/ThermalForge.appTurn on Launch at Login in the menu bar dropdown and it starts automatically on every boot.
Apple's default fan behavior is reactive: fans stay off until the chip is already hot, then ramp up to recover. This creates a repeating cycle during sustained workloads like renders, compiles, and ML inference:
- CPU/GPU runs at full clocks, heat builds unchecked
- Chip hits ~90°C, starts throttling clock speeds — 10-20% performance loss
- Fans finally ramp up
- Temps drop, clocks recover, fans slow down
- Heat builds again — repeat
This sawtooth pattern costs you sustained performance, wears hardware faster (thermal cycling stress on solder joints follows the Coffin-Manson fatigue model — damage scales with temperature swing amplitude, not absolute temperature), and forces fans to work harder because they're always recovering instead of preventing.
The Smart profile eliminates this. It monitors temperature velocity — not just where the temp is, but how fast it's rising — and ramps fans early enough to hold the chip below 85°C. The result: sustained peak clocks throughout your entire workload, less thermal cycling wear, and fans that run quieter overall because they never need to recover from a heat spike.
Apple doesn't do this because silence sells in store demos and most users never run sustained workloads. ThermalForge gives power users the choice Apple doesn't.
For best results, calibrate Smart to your specific machine:
sudo thermalforge calibrate # Standard (~28 min)
sudo thermalforge calibrate --mode quick # Quick (~10 min)
sudo thermalforge calibrate --mode optimized # Until stable (~35-50 min)Calibration stresses both CPU and GPU simultaneously using Metal compute shaders — the same combined-load approach used by Notebookcheck (Prime95 + FurMark) and Gamers Nexus for thermal testing. On Apple Silicon, CPU and GPU share the same die and unified memory, so combined stress captures real-world thermal behavior.
At each of 4 fan speed levels (min, 50%, 75%, 100%), calibration gradually increases load in steps (5% → 10% → 15% → 25%) while monitoring temperature. Load intensity is calibrated to produce realistic ~1°C/sec ramp rates matching real-world workloads (research: Notebookcheck, Max Tech), not synthetic maximum load. The performance ceiling is 85°C — the point where Apple Silicon starts throttling. If a fan speed can't hold the line at a given load step, calibration records that and moves on. The machine never exceeds the temperature threshold that Smart exists to prevent.
For each fan level, calibration records:
- Max sustainable load — the highest load this fan speed held below 85°C
- Temperature curve — how temp rose across load steps
- Cooling rate — how fast the fan speed brings temp down after load stops
Smart uses this data to make proportional decisions: match fan speed to current system load and temperature, keeping the machine below 85°C at all times.
| Mode | Time | What it does |
|---|---|---|
| Quick | ~14 min | 30s sample per load step (4 steps), 30s cool per level. Includes cooldown wait, fan spin-up, and transition discard. Good baseline data. |
| Standard | ~32 min | 75s sample per load step (4 steps), 2 min cool per level. Reliable data for all Macs. Recommended. |
| Optimized | ~35-50 min | Up to 2.5 min per load step, exits early when temperature stabilizes (<0.5°C change over 30s). Best data. |
Timing is based on measured thermal time constants of 90-120 seconds for Apple Silicon laptop heatsink assemblies (Notebookcheck M1-M4 MacBook Pro stress tests, Max Tech sustained performance testing). Mac Studio's larger thermal mass (~2-3x) is covered by Standard mode's timing.
Smart works without calibration — it uses a conservative default curve. Calibration makes it precise for your hardware.
By default, calibration stresses CPU and GPU simultaneously. For researchers who want to isolate thermal contributions:
sudo thermalforge calibrate --stress combined # CPU + GPU (default)
sudo thermalforge calibrate --stress cpu # CPU only
sudo thermalforge calibrate --stress gpu # GPU only (Metal compute)Do I need to re-calibrate every time I use Smart? No. Calibration runs once and saves the results. Switch between profiles freely — Smart always has your data.
Can I re-calibrate? Yes, at the same level or higher. Calibration data can't be downgraded — if you ran Standard, Quick won't overwrite it. Run Standard or Optimized to update. This prevents accidentally replacing good data with less accurate data.
Can I upgrade my calibration? Yes. If you initially ran Quick, running Standard or Optimized will replace it with better data.
What if I stop calibration early? Press the Stop button in the app or Ctrl-C in the terminal. Stress threads are killed immediately, fans reset to Apple defaults. No calibration data is saved. Smart continues to work with the default curve.
What if ThermalForge closes during normal use? The daemon's heartbeat watchdog detects the app is gone within 15 seconds and resets fans to Apple defaults. On next launch, the app resets fans to auto, then Smart picks up your calibration data when you activate it.
What does calibration save?
Two files in ~/Library/Application Support/ThermalForge/:
calibration.json— machine-specific thermal data that Smart readscalibration_<timestamp>.csv— every sensor reading taken during calibration (for research use)
Reset fans right now:
thermalforge autoKills the app and resets fans to Apple defaults. Calibration data is preserved.
Clear calibration and start over:
thermalforge calibrate --resetDeletes calibration data. Smart falls back to the default curve. No sudo needed.
Emergency reset (if nothing else works):
sudo killall ThermalForgeApp && sudo /usr/local/bin/thermalforge autoForce-kills the app and resets fans directly via the daemon.
Completely remove ThermalForge:
sudo thermalforge uninstallRemoves the daemon, binary, app, calibration data, and all logs. Clean slate.
If installed via Homebrew, run brew uninstall thermalforge first.
Calibration gradually increases CPU and GPU load while cycling fan speeds, capping temperature at 85°C. This is well within normal operating parameters for your Mac, but ThermalForge is provided as-is with no warranty. Use at your own risk.
thermalforge status # JSON output: fan speeds + temps
thermalforge max # Max fans (requires daemon or sudo)
thermalforge auto # Reset to Apple defaults
thermalforge set 4000 # Set specific RPM
thermalforge discover # Dump all SMC keys (for new hardware)
thermalforge watch # Monitor mode with auto-boost profiles
thermalforge calibrate # Calibrate Smart profile for this machine (sudo)
thermalforge calibrate --reset # Clear calibration data
thermalforge log # Record thermal data to CSV (1Hz, auto-delete 24h)
thermalforge log --rate 10 --duration 1h --no-expire # 10Hz for 1 hour, keep foreverTested on MacBook Pro M5 Max (Mac17,7). Should work on M1–M5 MacBooks.
Run thermalforge discover on your machine and submit a compatibility report.
| Machine | Chip | Status |
|---|---|---|
| MacBook Pro 16" (2025) | M5 Max | Tested |
| Mac Studio (2022) | M2 Ultra | Tested |
| MacBook Pro 16" (2021) | M1 Max | Tested |
SMC key names vary across chip generations — ThermalForge auto-detects at startup. The discover command dumps all keys so we can verify what your hardware uses. The more machines tested, the more robust ThermalForge becomes.
brew uninstall thermalforge
sudo thermalforge uninstallthermalforge uninstall removes the daemon, binary, app, calibration data, and all logs.
sudo thermalforge uninstallThis removes the daemon, binary, app bundle, calibration data, and all logs.
ThermalForge is a solo project but compatibility reports are hugely valuable. If you have an Apple Silicon Mac:
- Install ThermalForge
- Run
thermalforge discover --output discover.txt - Open a compatibility report and attach the file
That's it. Every new machine tested makes ThermalForge better for everyone.
No existing macOS tool exports structured thermal data with process correlation in a format designed for research. ThermalForge does.
- Data scientists studying thermal behavior across Apple Silicon generations
- Hardware engineers validating cooling solutions or thermal pad mods
- Developers profiling how their apps affect system thermals
- Researchers who need reproducible, citable thermal data for papers
thermalforge log # 1Hz, auto-delete after 24h
thermalforge log --rate 10 --duration 1h --no-expire # 10Hz, 1 hour, keep foreverEach session produces a self-contained folder:
| File | Contents |
|---|---|
| thermal.csv | Timestamped readings from every detected temperature sensor, fan RPM (actual + target), fan mode, at every sample interval |
| processes.csv | Top 5 processes by CPU utilization at every sample — the missing link between thermal data and what caused it |
| metadata.json | Machine model, chip, OS version, ThermalForge version, fan count, RPM range, sample rate, complete sensor dictionary, session start/end, total sample count |
- CSV + JSON sidecar — loads directly in pandas, R, Excel, or any data tool without a custom parser
- Raw SMC key names — no friendly labels that could be wrong across chip generations. Cross-reference against Apple hardware documentation directly
- Self-describing sessions — every log folder contains everything needed to interpret the data. Hand it to someone with no context and they can work with it
- Auto-delete by default (24h) — prevents disk bloat for casual users.
--no-expirefor researchers who need to keep data
ThermalForge has two separate log systems:
Session logs (thermalforge log exports) — the CSV/JSON research data. Auto-delete after 24 hours by default. Use --no-expire to keep data permanently. Stored in ~/Library/Application Support/ThermalForge/logs/.
Error log (thermalforge.log) — app events, profile changes, fan commands, temperature anomalies, safety overrides. 1GB cap — when the file reaches 1GB it starts fresh. Stored in ~/Library/Logs/ThermalForge/.
Researchers who need long-term data collection should use thermalforge log --no-expire for their sessions. The error log is diagnostic, not research data — it captures what happened and why, not continuous sensor readings.
- Thermal throttle state — capture Apple's
ProcessInfo.thermalState(nominal/fair/serious/critical) at every sample. Know exactly when and how hard the chip throttled. - Power draw — SMC power keys (PSTR, PCPT) to capture wattage alongside temperature. Watts correlate directly with heat generation.
- GPU utilization — current logging captures CPU processes but GPU compute workloads (Metal, ML inference) are invisible. GPU utilization fills that gap.
- Memory pressure — system memory pressure percentage at every sample
- Delta-T over ambient — report temperatures as both absolute and delta above ambient. This is the standard comparison metric used by hardware reviewers (Gamers Nexus, Notebookcheck) because absolute temps vary with room temperature.
- User markers — annotate the log mid-session ("started render", "switched profile") so data points have context when analyzed later
- Statistical summary — min, max, mean, standard deviation, P95/P99 for all sensors across the session. Time spent in each thermal state. Peak fan RPM.
A controlled testing framework for anyone who wants to understand their Mac's thermal behavior — modders validating thermal pad swaps, developers profiling their apps, engineers comparing cooling strategies.
thermalforge experiment --workload cpu --fan smart --duration 10m --label "smart-baseline"
thermalforge experiment --workload cpu --fan 75% --duration 10m --label "fixed-75"
thermalforge compare smart-baseline fixed-75Controlled variables:
- Fan speed: any profile, fixed percentage, or Smart
- Workload type: CPU stress, GPU stress (Metal compute), CPU+GPU combined, idle baseline, or any custom command
- Duration with automatic steady-state detection (temp change <0.5°C over 2 minutes)
- Ambient temperature input for Delta-T calculations
Metrics generated per experiment:
- Time-to-throttle — how long before the chip starts losing performance
- Time-to-steady-state — how long before temperature stabilizes
- Sustained performance score — average clock throughput over the test duration
- Statistical summary — mean, std dev, min, max, P95/P99 temps
Comparison reports:
- Side-by-side A/B results across experiments
- Automatic detection of statistically significant differences
- Export as CSV or formatted summary
Built-in workloads:
- CPU stress: saturates all cores with compute-bound work
- GPU stress: Metal compute shaders that load the GPU pipeline
- Combined: CPU + GPU simultaneously (the real-world worst case for Apple Silicon where CPU, GPU, and Neural Engine share the same die and unified memory)
- Idle baseline: 5-minute idle measurement before and after tests to establish reference
Opt-in anonymous upload of experiment results. Compare your machine against others with the same chip. See how your M5 Max thermal performance ranks against the distribution. Modeled after OpenBenchmarking.org — standardized methodology, community validation, machine fingerprinting by chip model (not serial number).
See ROADMAP.md for full specs and build plans.
MIT — free to use, modify, and distribute.