How to setup your Mac for web development: Terminal & app setup for .NET Core, Java (Android), Node, Go, and more…

I recently had a new Mac, and that made me revisit my terminal setup, which I’m now sharing with you.

The Terminal Itself

When I had my old MacBook in 2014, I wanted to go full experience, got iTerm2 and Oh My Zsh.

iTerm2 Vs Default Terminal

Later I learned that if I wanted to get a consistent experience, it’s easier to just use the built-in, and it’s not that bad.

I still made some modifications to it. I found most commands work better with dark shell so I duplicaed the “Pro” theme and used it (a duplicate was just to increase font size).

I also used bash-git-prompt (via Homebrew) to get a beautiful prompt with full path and git status.

And there’s a lot more when I talk about dot files and .bashrc…

Oh My Zsh Vs Bash

I also learned that from time to time you’d hit a few subtle script differences between Oh My Zsh and the default Bash, usually arround having to quote some strings that Bash doesn’t require quoting. This made copying and pasting commands from tutorials etc a pain sometimes, so I defaulted to Bash this time.

You see the pattern here, I try to utilise the power of defaults.


There’re a lot more Brew apps than there are for Mac Ports. Some of you might even not have heard of the latter, so, I just use Brew.

One thing I learned over time is that if something has an installer, I’d better use that installer itself, unless the installer is really a shell script itself.

I’ll talk about each case separately below.

Terminal Dot File Tweaks: .profile, .bash_profile, and .bashrc

I got quite confused between the 3 files at first, and head to learn about all this crap about login shells and non login shells, and how Mac is not standard itself. I ended up changing my files as below:


Run the terminal-type-agnoistic (forgive my lack of clever wording here) .profile file if it exists:


Just run the ~/.bashrc file if it exists


That’s where I end up putting all my terminal customizations. The next steps are to divide these into smaller files kept in a directory really.

For example, that’s where I enable the git prompt, which was by following their README by the way if the code feels complex:

And also show hidden files in completions:

Relative .bashrc Files!!

This is a good one, and the motivation for writing this blog post, seriously.

I like to have the latest version of everything I use, but I had a React Native project that required Node 8 (for some dependencies that are not updated yet), and Java 8 (for Android).

I decided that I’m going to install multiple versions of Java and Node (via NVM), and pre-select the correct version in my project folder using a .bashrc file.

I wanted the versions to be pre-selected for me so I have to remember to select them less often. Then came the idea:

What if the terminal could load a .bashrc file for me automatically based on directory?

I usually use VS Code integrated terminal, or use its menu to start the terminal app in the project directory, so that will work great.

But the .bashrc file will have to live outside outside of the repository, because I cannot modify the repository for everyone else or a file that gets lost with git clean -dfx, so it needs to be something like:

And I did it simply by adding the following to the ~/.bashrc file, the one in my home directory which gets loaded automatically as I explained:

Remember that I’m a true newbie when it comes to this stuff. There’s probably a better way to write this, and I probably should have capitalised bashrc_dir, and sure violated other bash conversions, but it works!

I’ll talk below about what it enabled me to do.

Bash Completions

For a long time I felt that I wasn’t getting any tab completion (auto-complete menu on pressing tab after a command) in my new setup. At first I thought it was just Bash vs Zsh, but I recently learned that I can enhance it a bit.

I installed bash-completion using Homebrew, which was not enough by itself, so I added the following to my home dir ~/.bashrc:

Now I started seeing completions. For example if I type npm run inside a folder with package.json file, and press TAB twice (not sure why twice), I see a list of npm scripts. Similarly if I’m in a git folder and type git checkout TAB TAB, I get to see all branch name (or a warning if there are so many).

Watching Files for Development

A lot of stuff, especially NodeJS stuff, watch files for changes during development. Think Webpack or TypeScript compiling your files, or React Native packager watching files to send them to mobile device app, etc.

To make this work with no errors, there’s something to do, and something NOT to do.

DO NOT install fsevents or watchman using NPM global install. This will only cause issues.

Instead, just install watchman using Homebrew:

If you still have watchman or fsevents errors. Check if you have either of them installed via NPM, remove them, remove watchman from Homebrew and install it again.


I installed git via Homebrew. That way it’s pretty easy to update it. I also installed bash-git-prompt similarly as I mentioned above.


Another tool I installed via Homebrew is git-credential-manager, which allowed me to login to Visual Studio Team Services (VSTS) git repositories in a slightly fancier way (using browser login, that’s later cached).

GUI Client

Coming from Windows, I originally cired for lack of a good alternative for Git Extensions. SourceTree was the closesth but wasn’t close enough, and GitHub for Mac was overly simplified for me, that it felt lacking.

Nowadays I’m pretty happy using Fork which I got using the official installer. It is a great git client for when I want to look as graphical log or mess with my changed files diff before committing. I still use the terminal for switching branching, pulling/fetching/pushing, etc.

Terminal Intgeration

In Fork preference, the Integration tab, you’ll find a button to install fork as a command to your terminal. This allows me to type fork . in the terminal in any folder in my git repository to open that repository in Fork.

Diff Tool

For some reason my head refuses to understand any 3-way diff tool other than Kdiff3, which used to come with Git Extensions. I still use it now, installed via brew cask.

VS Code

Since we are talking about modifying files here, I’d like to talk about how I modify them. I use VS Code, please do not hate me Vim users!

I use the Insiders edition of VS Code. This is like a daily build of VS Code. You get all new features weeks before others do, which is awesome. The Insiders edition is fairly stable in my experience, and the update is very quick on Mac too (unlike Windows), so it’s awesome.

To get the Insiders edition, I just google VSCode Insiders and click on first result.

VS Code To Terminal

The only caveat of frquently updating VS Code is: because I don’t know when I might want to restart my VS Code for update, I avoid running long running tasks in its terminal.

I can press CMD+SHIFT+P to show command palette, and type new t then select Open New Terminal to open a new tab of the default terminal app, started in the project folder. You’ll see later why this is so cool.

Terminal To VS Code

To easily open files and folders in VS Code from the terminal, I can press CMD+SHIFT+P to show command palette, and type install then select the command that installs the code-insiders command in my PATH.

Sometimes I feel that this is a long command though, completion works startingfrom code-, I probably should add just code as an alias.


I wasn’t sure whether to go with installer or brew for this one. I knew I’ll have to fiddle with paths anyway, so, I thought I’d use Brew so it’ll be more transparent to me. I used brew cask to install both java (latest) and java8.

In my user ~/.bashrc file I added:

Java 8 for Android

In my project specific .bashrc, I added:

That’s a lie. I only did when I was writing this post. I made up the first two lines. My real old code looked like:

Note the jdk1.8.0_181 bit, which is whatever exact Java 8 version I got from brew cask. I replaced it in the first snippet to be dynamic, and it might be worth mentioning that I made up the JDK_ALL and JDK_8 variables.

To test that it still works, I opened my project in VS Code, and in the terminal I typed java -version, must be a single - BTW!

Installing Android Itself

After struggling a lot with Android and Homebrew on my new machine, knowing that I got it to work somehow before on my old MacBook (which was out for repair at the time of new machine setup), or did I? I decided to go with the official installer for it.

I googled for Android, downloaded Android Studio from it, and then ran it to install the actual Android SDK the first time it opened.

I later discovered issues (maybe) specific to my active project, like Java version as I mentioned, but also found myself having to set a few extra global variables to ny home ~/.bashrc file – besides project-specific Java 8 which I mentioned separately above:

All the usr/local stuff is probably from Homebrew, could have been replaced with $(brew prefix), and all ~/Library/Android/sdk is from official install.

Maybe next time I get a clean environment I’ll do it differently. I don’t know!

.NET Core

I used the official installer for .NET Core runtime and SDK as it allowed me to easily install multiple versions of the SDK, which Brew didn’t. I did have a project pinned to a specific SDK version via global.json in its repository.

I went to, clicked on Download, looked at the end of the page for download archives, checked for latest current version for my machine, and for 2.0 for my project, then found the exact version fo the SDK in the 2.0 page.

Note that SDK 2.1.2 is for .NET Core is NOT the same as SDK 2.1.200, and that both are for .NET Core 2.0 not 2.1!


I installed both Node and nvm (Node Version Manager) via Homebrew.

I don’t relying on NVM too much. Things can get funny with global NPM dependencies when you switch Node versions using it, so, I keep that to a minimum. Here’s the idea:

In my home ~/.bashrc, I added the following lines:

The > /dev/null 2>&1 bit is to hide a false negative error from the console, that I get about NPM prefix. You see I try really hard to hide that error in other ways in vain!

Then, in the folder right above my project get repository, where I had another relative .bashrc file as I mentioned above, I added:

I can confirm that I have a different version of Node by opening my project VS Code workspace, and typing node -v in the terminal.

Upgrading NPM

With the above setup, it’s worth noting that I get 2 NPM installs, one that’s the global / default, and one that’s specific to my project.

Node 8 comes with a slightly outdated version of NPM, so, to update that, I opened the VS Code terminal inside my project workspace, ran node -v to confirm it’s picking it correctly, then I upgraded NPM by running npm install -g npm, and after it finished, I ran npm -v to confirm it’s picking the new version.

I did the same thing with my global Node install BTW. I told you I love to use latest versions of my stuff.

Golang (Go)

This was another silly one. I remember struggling with code paths on my old machine after installing via Homebrew, so, like Android, I just went to the official website and installed it via the official installer.

After that, I learned how that if your Go code doesn’t live under ~/go/src/project-name, you can get a lot of problems because of GOPATH environment viable. I really wanted to fix this!

That annoying problem is what prompted me to finally blog about relative .bashrc files, after posponing that for a very long time.

The following snippet, which I’m experiencing with in a project-specific .bashrc file, but can also be in the home ~/.bashrc file, fixes this problem:

Turns out you can set multiple GOPATH folders, separating them by : (or ; in Windows). I also had to set GOBIN as you see in the script comment.

RVM (Ruby Version Manager)

I don’t do Ruby really, but my current project had a script that ues it. There’s no homebrew option for RVM, and following the official instructions -which you get by googling RVM– failed on my Mac.

The error is around a pre-install command you need to run, which uses some signing / signature verification tool called gpg, which is not available on Mac.

I found this blog post which suggested another command to run before the installation:

Now I was able to follow up with the official install.

I also made sure I have the following in my home dir ~/.bashrc of course, this code is a copy-paste from instructions:

Performance And Battery

Away from terminal really, more into the menu bar, but still especially useful for me as a developer and pro user, I have a few apps to ensure I ge the best performance and battery life I can from my Mac

Macs Fan Control

MacsFanControl is an almost-necessary free app to prevent my i9 MacBook 2018 pro from throttling while I’m doing heavy work.

Turbo Boost Switcher Pro

I bought the paid (Pro) version of Turbo Boost Switcher so that I can turn off Intel Turbo Boost automically when I’m running on batteries.

It’s a of the opposite of the previous app I know, but quite often when I’m running on battery I need it to stay alive longer. Or when I don’t, I just turn off the auto mode and explicitly turn turbo boost on, and continue working.

Battery Health

Battery Health is another paid app for the battery, but this time just for monitoring.

I like to know how my overall battery life going over the year, and this is the app for that. But I also LOVE to see an estimate time of how long it’s until I run out of battery, a feature that used to be built into macOS itself then got removed.

Touchbar Tweak

If you are like my, you probably hate a lot of things about the MacBook 2016+ keyboards, especially the touchbar, especially how the Esc key has no feedback. Yuck!

A few people thought that the best tweak for the touch bar is by giving it Haptic feedback (a vibration feel on touch). Until Apple implements that, we can use the free HapticKey app, which vibrates the touchpad when you tap the touchbar.

It’s not the real thing, but it’s close!


Apple, if you ever see this, please in addition to haptic feedback on the entire touchbar, please also change the Esc key to the same kind of physical key you use for the power button, PLEASE!

Other Tools

I defintely missed a few more here. There are specific extensions and settings in VS Code, fixes for common Node package install issues, and more, but each feel like they should be their own blog post.

For now, I’ll mention that I also have these in my home .bashrc folder, and I don’t remember now what problem they were fixing – I should have added comments, I know!

There’s also another tool I have called bash-it. It supposedly adds some nice stuff to Bash that makes it closer to Zsh, but I haven’d noticed any specific benefit yet. They also have customization bash prompt themes, but I use bash-git-prompt as I mentioned.

And I use SnagIt for taking screenshots, and Audacity for fine-tuning audio of my YouTube videos, which I haven’t posted in a while, so, that doesn’t matter.

I also use this old tool on Github called RDM when I want to experiment with non HiDPI resolutions (which seem to increase the battery life slightly, unless I’m imagining), but the effect is not confirmed, so who case.

And if it counts, I installed Docker using the official installer, and using Docker for Mac official support for Kubernetes to install that.

Conclusion & Updates

When I try to modularize my ~/.bashrc file, and check my old Mac for anything else I had in the past that’s still useful, I might put it all on github and add it to the post. Make sure you follow me on Twitter for updates.


Share With Friends:

How did I learn that?

As a bonus for coming here, I'm giving away a free newsletter for web developers that you can sign up for from here.

It's not an anything-and-everything link list. It's thoughtfully collected picks of articles and tools, that focus on Angular 2+, ASP.NET (4.x/MVC5 and Core), and other fullstack developer goodies.

Take it for a test ride, and you may unsubscribe any time.

You might also want to support me by checking these out [Thanks]: