Staring at my terminal at 11pm last Thursday, my M3 MacBook Pro running Sonoma 14.4 was hot to the touch with fans roaring just to test one API endpoint. Booting our local dev environment spun up UI-automation, iOS simulators, macOS native debuggers, and a distributed logging sidecar by default. Running Node.js 22.4.1 for a simple logic bug doesn’t require the entire observability stack. So I ripped it all out.
The Monolithic Dev Environment is Killing Your Laptop
So there I was, staring at my terminal at 11pm last Thursday. My M3 MacBook Pro (running Sonoma 14.4, if you care) was literally hot to the touch, and the fans sounded like a jet engine. I just wanted to test a single API endpoint. But booting up our local dev environment decided to initialize the UI-automation suite, the iOS device simulators, our heavy macOS native debugging tools, and a massive distributed logging sidecar.
Why? Because historically, we just turned everything on. It’s a terrible habit we’ve accepted as normal.
We throw every possible diagnostic tool into our local setups because we think it saves time. But when you’re running Node.js 22.4.1 and trying to step through a simple logic bug, you don’t need the entire observability stack running locally. It’s impossible to know what tools a developer will actually need for a specific task. Assuming they need all of them is how you ruin productivity.
I finally snapped and ripped it all out. Now? Simulator tools, heavy debugging, and logging agents are strictly opt-in.

The Opt-In Workflow Approach
I switched our entire team to a model where the default state is bare-bones. If you want the extra toys, you ask for them. We handle this either by setting an ENABLED_WORKFLOWS environment variable to a CSV list, or—my preferred option—via a local .devconfig.yaml file.
Here’s the thing. If you just tell people “use environment variables,” your junior developers will sit there in silence, too afraid to ask why their breakpoints aren’t hitting. You have to build an interactive setup wizard.
I wrote a quick CLI command that gives you a checklist. It generates the config file for you based on what you’re actually working on today.
import yaml
import inquirer # I use the inquirer library for the interactive CLI
import os
def generate_dev_config():
questions = [
inquirer.Checkbox(
'workflows',
message="Which tools do you need for this session?",
choices=[
'api-debugging',
'ui-automation',
'macos-native',
'device-simulators',
'heavy-logging'
],
default=['api-debugging']
)
]
answers = inquirer.prompt(questions)
config = {
'workflows': answers['workflows'],
'log_level': 'DEBUG' if 'heavy-logging' in answers['workflows'] else 'WARN'
}
with open('.devconfig.yaml', 'w') as file:
yaml.dump(config, file)
print(f"Config saved. Enabled workflows: {', '.join(answers['workflows'])}")
if __name__ == "__main__":
generate_dev_config()
Run the setup command, pick what you need, and start your server. That’s it.
The Real-World Impact (and One Nasty Gotcha)
I benchmarked this after rolling it out to the team last month. With the old “everything on” approach, our local environment took 4m 12s to spin up and ate about 6.8GB of RAM. With the opt-in config? We dropped to 45 seconds and just 1.4GB of RAM for a standard backend workflow. The difference in developer sanity is hard to measure, but I haven’t heard a laptop fan spin up in weeks.
But there is a gotcha you need to watch out for.
If you use this modular approach with VS Code’s launch.json, you need to make sure your debugger config explicitly checks for these workflows before trying to attach. I spent two hours last Tuesday debugging my own debugger. It kept throwing an ECONNREFUSED on port 9229. Why? Because VS Code was trying to attach to a Node debug port that our startup script intentionally didn’t open because I hadn’t opted into the api-debugging workflow. Classic.
You have to add a pre-launch task that validates the YAML file, or just conditionally open the ports in your startup script based on the config.
Stop Punishing Your Hardware
By Q2 2027, I expect most major frameworks to adopt this modular, opt-in approach for local dev tools by default. The monolithic dev environment is dead. We have too many tools, too many sidecars, and too much telemetry to run it all locally without melting our machines.
If your team is still loading every single tool on startup, take an hour and write a setup script. Your RAM will thank you.
Questions readers ask
How do I stop my local dev environment from overheating my MacBook?
Switch from a monolithic setup to an opt-in workflow. Make the default state bare-bones and load simulator tools, heavy debugging, and logging agents only when explicitly requested via an ENABLED_WORKFLOWS environment variable or a local .devconfig.yaml file. After this change, the author’s team dropped startup from 4m 12s and 6.8GB of RAM to 45 seconds and 1.4GB, and laptop fans stopped spinning up.
How much RAM can you save by making dev tools opt-in?
The author benchmarked a typical backend workflow before and after rolling out the opt-in config. The old “everything on” approach consumed about 6.8GB of RAM and took 4m 12s to spin up. With opt-in workflows selecting only what’s needed for the current task, RAM usage fell to 1.4GB and startup dropped to 45 seconds, a roughly 5x reduction in memory footprint.
Why am I getting ECONNREFUSED on port 9229 in VS Code after making dev tools opt-in?
VS Code’s launch.json is trying to attach to a Node debug port that your startup script intentionally didn’t open because you didn’t opt into the api-debugging workflow. Fix this by adding a pre-launch task that validates your .devconfig.yaml file, or conditionally open debug ports in your startup script based on the enabled workflows. The author lost two hours debugging exactly this issue.
How do I build an interactive CLI wizard to generate a dev config file?
Use Python’s inquirer library to present a Checkbox prompt listing workflows like api-debugging, ui-automation, macos-native, device-simulators, and heavy-logging. Capture the developer’s selections, then write them to a .devconfig.yaml file using PyYAML, setting log_level to DEBUG when heavy-logging is chosen and WARN otherwise. Developers run the command, pick what they need for the session, and start their server.
