mac development logo

In this post I describe my configuration log for setting up a Mac (INTEL or ARM) as a development machine. I install several graphical and command-line applications that are important for using a Mac as a development workstation.

The installation order can be varied, but this is what I recommend starting from a fresh macOS installation.


Note: My guides for preparing each OS for software development: macOS, Linux, and Windows.

First Steps

I’ll work from the CLI with Terminal.app during the initial setup, although I’ll quickly install iTerm2.


Xcode or Xcode Command Line Tools

xcode logo

This is mandatory – install the Apple command line tools (also known as Xcode command line tools) because some tools will require them later.

Installing Xcode is optional, only if you’re going to develop for macOS, iOS, watchOS, and tvOS. Depending on what you decide, the options are:

  • Option 1: Install Xcode along with the Apple command line tools:
    • Install Xcode from the Apple Store. Open it once and install what you need
    • Then from the CLI: xcode-select --install and sudo xcodebuild -license accept
Xcode startup screen.
Xcode startup screen.
  • Option 2: Just the Apple command line tools:
    • Install them from the CLI: xcode-select --install and sudo xcodebuild -license accept

iTerm2

iterm2 logo

Much better than Terminal.app – window transparency, full screen mode, split panes, Expose tabs, Growl notifications and keyboard shortcuts, customizable profiles, etc. To install it:

  • Download the program from iTerm2 and copy it to Applications

A couple of tips:

  • If you’re migrating from another Mac to a new one, you can copy the configuration from the old one, it’s here:
    • ~/Library/Preferences/com.googlecode.iterm2.plist
  • If you experience the problem: “When iTerm starts it takes a long time to show the prompt”, it’s solved with sudo xcodebuild -license accept
  • Enable a shortcut in Finder to open an iTerm when the cursor is on a Finder folder.
    • System Settings -> Keyboard -> Keyboard Shortcuts -> Services
    • -> Files and Folders -> New iTerm2 Tab Here -> Ctrl Shift T

Nerd Fonts

Highly recommended – in fact, you’ll need it for Oh-My-Posh which I install later…

  • From the Nerd Fonts repo > Fonts Downloads. I search for and download FiraCode Nerd Font (it’s the one I like, but you can choose any). Unzip the file, select all .ttf files > right-click > Open > Install all.
  • I configure it as the default font in iTerm: Settings -> Profiles -> Default -> Text -> Font FiraCode Nerd Font

Homebrew

homebrew logo

Before continuing, this is essential – as a developer with a Mac, you need Homebrew (or brew for short). macOS comes with all kinds of Unix commands (being based on FreeBSD) and many utilities, but if you want to stay up to date and install almost any tool or software, you need Homebrew.

The advantage is that you can install everything (in parallel, without messing up macOS). A ton of super interesting open source software, low-level tools, command line utilities, applications, compilers, languages, etc. – you can even install MongoDB (see below).

Installation:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

devcli

I’ve created a GitHub repository called devcli to automate the installation of some tools – CLI utilities for Unix-like systems such as macOS, Linux, WSL2 (and also Windows). I was tired of wasting a couple of hours with new systems, parameterizing, tools, fonts, helper scripts. I automate everything with a single command. Check out the repository and if it works for you:

  • Set up your user so sudo works without asking for a password
    • Terminal.app > id (note your <short-username>)
    • Terminal.app > sudo su -
    • Edit the file nano /etc/sudoers.d/10-usuario and add a line <short-username> ALL=(ALL) NOPASSWD:ALL
    • Exit and re-enter Terminal, test if this command works: sudo cat /etc/sudoers

Installation:

bash <(curl -fsSL https://raw.githubusercontent.com/LuisPalacios/devcli/main/bootstrap.sh)

Zsh

If you’ve run devcli, skip this section.

macOS includes Zsh (short for “Z Shell”), much more powerful than Bash. I’ve left my configuration files (which I always install) in this GitHub repository: My zsh files. I open Terminal.app and download my .zshrc.

curl -LJs -o ~/.zshrc https://raw.githubusercontent.com/LuisPalacios/zsh-zshrc/main/.zshrc

Important: Edit it with nano and adapt it to your username, directories, PATHs, etc. It’s set up by default to work with Oh My Posh. Next I install Homebrew, iTerm2, Nerd Font, and Oh My Posh.


Oh My Posh

If you’ve run devcli, skip this section.

Oh My Posh advertises itself as “a Prompt engine for any Shell”. It allows rendering the PROMPT in a very advanced way, but what I like most is how it handles Git, where the biggest problem is PROMPT rendering. None of the advanced renderers I’ve tried (including Starship) are as efficient as Oh My Posh. For this reason alone it has become my choice, above Starship.

brew install jandedobbeleer/oh-my-posh/oh-my-posh

Note: Check my copies of .zshrc and .oh-my-posh.yaml that were automatically downloaded in the devcli section. I always upload the latest versions here.


Visual Studio Code

vscode logo

Visual Studio Code is a source code editor developed by Microsoft for Windows, Linux, macOS, and Web. It includes support for so many things it’s impossible to explain here. With the immense diversity of features, plugins, and supported languages, you can use it as an IDE for any project.

Installation:

A couple of tips:

  • To conveniently launch it from iTerm2, with VSCode running, press CMD-SHIFT-P and install the ‘code’ command in PATH.
Install the `code` command in PATH
Install the `code` command in PATH
  • I create an alias in my ~/.zshrc to quickly launch the program from the CLI.
# Alias to launch VSCode from CLI with "e"
alias e="/usr/local/bin/code"

Settings and Synchronization: Check out the post VSCode settings and extensions for more information.


Git

If you’ve run devcli, skip this section.

git logo

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. There are several installation options for the command line client (original source) – in my case I use Homebrew.

Installation:

brew update && brew upgrade
brew install git

source ~/.zshrc

I create the ~/.gitconfig and ~/.gitignore_global files, which you can download like this:

curl -s -O https://gist.githubusercontent.com/LuisPalacios/0ee871ee236485d4a064179b16ada400/raw/348a8a448095a460756f85ef0362521b886b0a2e/.gitconfig
curl -s -O https://gist.githubusercontent.com/LuisPalacios/6923f8cc708ce10f3bd4a6772625fb0c/raw/65d0ed6acba83ece4db78228821589212b9f9f4b/.gitignore_global

# Edit to customize
e .gitconfig

As a GUI client I use GitKraken. You can find more info about git in this GIT cheatsheet and GIT in detail.


SSH Public-Private Key

ssh logo

Now is a good time to set up your public/private key pair for connecting to remote hosts and/or using it with Git server(s). The SSH public-private key is an authentication and encryption system used for the connection between a client and a server. A pair of keys is used: a public key and a private key. The two most common use cases are:

  • Connecting from my Terminal to a remote server.
  • Connecting my git client to a remote Git server (e.g., github.com)

I create my public-private key, which creates two text files under ~/.ssh.

➜  ~ ssh-keygen -t ed25519 -a 200 -C "luis@mihost" -f ~/.ssh/id_ed25519
:
Enter passphrase (empty for no passphrase):            <=== If you set one, this is what the host where you copy your .pub will ask
Your identification has been saved in /Users/luis/.ssh/id_ed25519   <== PRIVATE Key. NEVER SHARE IT
Your public key has been saved in /Users/luis/.ssh/id_ed25519.pub   <== PUBLIC Key. This content is what you share!!
:

The content of the public key file is shared with the remote server (github or a Linux for remote terminal), while the private key stays local. Oversimplifying it, my public key that I give to GitHub will be used to encrypt information that only I, who possess the matching private key, can decrypt, allowing us to communicate.

In the case of GitHub, you can use this method (SSH public-private) for direct access to your account and to modify repositories securely, without needing to log in (https with username and password). It’s important to note that you must keep your private key secure, since if someone else has it, they can access your account and repositories.

Your public key content:

  • Is usually placed on remote Linux machines you want to connect to: appending it to the end of the ~/.ssh/authorized_keys file
  • If you didn’t set a password, those machines won’t ask for anything – you’ll get in directly, as long as you connect from a machine with the Private key :-)
  • On Git servers, through their GUI, in your account properties.

You have a couple of additional posts at SSH and X11 and SSH on Linux

LLVM/CLANG

If you want to develop with C++ using CLANG, after installing Xcode and Homebrew, the next steps would be:

brew install llvm       # Installs the latest version.
brew install llvm@17    # If you also want to install a specific version.
brew install cmake      # In case you use cmake.
brew install ninja      # In case you use ninja

Java

java logo

We can install JRE (Java Runtime Environment) to run Java applications or the JDK (Java Development Kit) to develop and run Java applications.

In my case I obviously install the JDK, which brings tools like the compiler (javac), the binary disassembler (javap), the debugger, etc., and every JDK installation includes JRE. I recommend checking this image of the Java component structure.

Installation:

  • Go to Java SE Development Kit and download the JDK 20 version for macOS. In my case I chose the ARM64 DMG Installer
Downloading and installing the Java SDK
Downloading and installing the Java SDK

Once installed, we do our proof of concept from iTerm

$ mkdir -p ~/Desktop/hola
$ cd ~/Desktop/hola
$ cat > HolaMundo.java << EOF
public class HolaMundo {
  public static void main(String[] args) {
  System.out.println("Hola Mundo!");
 }
}
EOF

$ javac HolaMundo.java
$ ls -l
total 16
-rw-r--r--@ 1 luis  staff  423 22 abr 15:22 HolaMundo.class
-rw-r--r--@ 1 luis  staff  111 22 abr 15:21 HolaMundo.java

$ java HolaMundo
Hola Mundo!

Here are some useful references:


Eclipse

eclipse logo

You could use Visual Studio Code as an IDE but it’s most common to install Eclipse – it’s The platform for working with Java, and much more, really with open source, cross-platform programming tools for developing Applications.

It has typically been used to develop IDEs (Integrated Development Environments), like Java’s own (Java Development Toolkit - JDT).

Installation:

  • Go to Eclipse and download the Eclipse Installer.
  • Copy it to Applications, you can install other options now or later
  • Run it from Applications
Downloading the ARM version of Eclipse Installer for Mac
Downloading the ARM version of Eclipse Installer for Mac
  • Install “Eclipse IDE for Java Developers”.
Installing Eclipse IDE for Java Developers
Installing Eclipse IDE for Java Developers

A tip:

Python

python logo

Python is an interpreted, versatile, and easy-to-learn programming language. What I like most is that it’s very readable and supports multiple paradigms like object-oriented, functional, and imperative programming. Many tools need it and it has many use cases. Although I don’t use it much myself, I always install it.

Pip is a fundamental tool for managing Python packages. It’s the system used to install and manage third-party libraries from the Python Package Index (PyPI), Python’s official repository.

venv venv is a module included in Python that allows creating virtual environments. A virtual environment is an isolated space on the system where you can install Python packages and libraries independently, without affecting or being affected by other Python installations on the system.

Installation:

brew install python     <--- (installs python3 and pip3)

Exit Terminal and re-enter. Verify that when running python3 and pip3 the Homebrew version is being executed

luis ❯ where python3
/opt/homebrew/bin/python3
/usr/bin/python3
luis ❯ where pip3
/opt/homebrew/bin/pip3
/usr/bin/pip3
luis ❯ python3 --version
Python 3.13.5
luis ❯ /opt/homebrew/bin/python3 --version
Python 3.13.5
luis ❯ pip3 --version
pip 25.1.1 from /opt/homebrew/lib/python3.13/site-packages/pip (python 3.13)

Although it might seem a bit obsessive, it’s important. Keep in mind that macOS comes with Python3 but an older version (3.9.x).

Homebrew places executables in /usr/local/ on Intel Macs and in /opt/homebrew on ARM Macs. If needed, you can create aliases.

# Add to the end of ~/.zshrc
# Mac ARM
alias python="/opt/homebrew/bin/python3"
alias pip="/opt/homebrew/bin/pip3"
# Mac Intel
#alias python="/usr/local/bin/python3"
#alias pip="/usr/local/bin/pip3"

I recommend always using a virtual environment (venv), to avoid filling your system globally with libraries. I always do a proof of concept when I install Python.

Prepare the project directory and the libraries it will use:

proyecto ❯ python3 -m venv myenvtest
proyecto ❯ source myenvtest/bin/activate
proyecto ❯ where python3  <== IMPORTANT, I CHECK THAT IT CHANGED MY PATH +---------------+
/Users/luis/Desktop/proyecto/myenvtest/bin/python3 <== AND PUTS THE VENV DIRECTORY FIRST <--+
/opt/homebrew/bin/python3
/usr/bin/python3
proyecto ❯ python3 -m pip install requests idna
proyecto ❯ python3 -m pip freeze > requirements.txt

I create a Python program called test.py

# test.py
# Test script to check internet connection

import requests

try:
    response = requests.get('https://httpbin.org/ip', timeout=5)
    if response.status_code == 200:
        data = response.json()
        ip = data.get('origin', 'IP not found')
        print(f'Your IP address is: {ip}')
    else:
        print(f'Error: HTTP response {response.status_code}')
except requests.exceptions.RequestException as e:
    print(f'Connection error: {e}')

I run the program

proyecto ❯ python3 ./test.py
Your IP address is: 9.13.11.48

You now have python installed and working. We can delete the test directory.

cd ~/Desktop
rm -fr proyecto

Integration with Visual Studio Code

Here are some recommendations for integrating Visual Studio Code and Python

If you have plenty of time, a good article: Advanced Visual Studio Code for Python Developers

Ruby

ruby logo

macOS already comes with Ruby, but I’m going to install the latest version with Homebrew in parallel. I need Bundler and Jekyll (see below) to work on my blog locally (more info here). Ruby is an interpreted, reflective, object-oriented programming language, created by Japanese programmer Yukihiro “Matz” Matsumoto, who began working on Ruby in 1993 and publicly released it in 1995.

Installation:

brew install ruby

Ruby doesn’t automatically link to Homebrew’s installation directory after installation because it could conflict with the Ruby that comes with macOS. In my case I do want this new Ruby to be executed, so I add its PATH in the .zshrc file and also the location where I’ll install future “gems” (~/.gems/bin).

# LuisPa: Adding Ruby and future Gems paths to my .zshrc file
# Mac ARM version
export PATH="/opt/homebrew/opt/ruby/bin:~/.gems/bin:$PATH"
# Mac Intel version
#export PATH="/usr/local/opt/ruby/bin:~/.gems/bin:$PATH"

To install gems without needing to be root (i.e., without sudo) and have everything installed in my user directory, I create the ~/.gems directory and modify ~/.zshrc:

mkdir ~/.gems
  • Add to the end of ~/.zshrc
export GEM_HOME=~/.gems
export PATH=~/.gems/bin:$PATH

| Remember to exit iTerm and re-enter or run source ~/.zshrc to find the new executables |


Jekyll and Bundler

jekyll logo

I need these to work on my blog locally. Jekyll is a simple generator for static websites with blog capabilities (you create markdown files and it generates the HTML). It’s written in Ruby by Tom Preston-Werner (GitHub co-founder) and it’s blazingly fast. Bundler is a software package manager that facilitates working with Jekyll and its dependencies.

Installation:

gem install jekyll bundler

| Note 1: They’re installed in /Users/luis/.gems/bin/jekyll, so it’s very important that you updated your PATH in the previous step. |

| Note 2: After installation I get a message: A new release of RubyGems is available: 3.4.10 -> 3.4.12 and it suggests running gem update --system 3.4.12. I ignore it – I’ll follow the update processes that brew does when appropriate |

Once I have everything above installed, I do a proof of concept:

jekyll new test
  New jekyll site installed in /Users/luis/test.
cd test
bundle add webrick
bundle exec jekyll serve

From a browser I connect to http://127.0.0.1:4000/ and see that it works!


Node.js

nodejs logo

Node.js is a cross-platform, open source, server-side runtime environment based on JavaScript, asynchronous, with event-driven I/O architecture based on Google’s V8 engine. It was created with the focus of being useful for building highly scalable network programs, such as web servers.

I could install Node.js from its official site, but that requires sudo. If I install it with Homebrew I have it in userspace, don’t have to touch the PATH, and it’s also easier to install packages with NPM.

Installation:

brew install node
node -v
  v19.9.0
npm -v
  9.6.3

Let’s do a super simple example:

Quick test with Node.js.
Quick test with Node.js.

MongoDB

mongodb logo

MongoDB is a NoSQL, document-oriented, open source database system. Instead of storing data in tables as done in relational databases, MongoDB stores BSON data structures (a specification similar to JSON) with a dynamic schema, making data integration in certain applications easier and faster.

I install MongoDB 6.0 Community Edition on macOS using Homebrew (source). I use a tap, which only needs to be done once. It consists of adding an (external) repository to the list of locations Homebrew installs from.

Prepare the installation:

brew tap mongodb/brew
brew update

Installation (includes the mongod server, the mongos sharded cluster query router, and the mongosh shell):

brew install mongodb-community@7.0
IntelARM
Configuration/usr/local/etc/mongod.conf/opt/homebrew/etc/mongod.conf
Log/usr/local/var/log/mongodb/opt/homebrew/var/log/mongodb
Data/usr/local/var/mongodb/opt/homebrew/var/mongodb

Now let’s run MongoDB

  • Start or Stop MongoDB as a macOS service using brew
brew services start mongodb-community@7.0
First time starting
First time starting
brew services stop mongodb-community@7.0

If macOS won’t open mongodb or mongosh for security reasons: Preferences -> Security and Privacy pane > General > mongod Open Anyway or Allow Anyway

Check that it started and listens on localhost on the default port 127.0.0.1:27017

netstat -na|grep -i 27017
tcp6       0      0  ::1.27017              *.*                    LISTEN
tcp4       0      0  127.0.0.1.27017        *.*                    LISTEN
a3f97c9f1c2bb4f1 stream      0      0 a3f97cad866b9521                0  0 0 /tmp/mongodb-27017.sock

And we can monitor the Log

tail -f /opt/homebrew/var/log/mongodb/mongo.log
Monitoring the server Log file
Monitoring the server Log file

An example program

Here’s a reference to a small GitHub project where you can test npm and mongod.


Jupyter Lab

Jupyter Lab is a web application that allows coding, execution, and “documentation”. The latter is one of the most interesting parts of the project – you can have documentation and code together and have it execute.

I’ve documented the process in another, older post. You can skip the Python part since this one is more up to date, but the rest may be useful: Python and JupyterLab on macOS.


VirtualBox and Vagrant

| Note: This section has only worked for me on a Mac with an Intel chip, so you’ve been warned – for now I haven’t found how to emulate a Linux or Windows ARM with VirtualBox and Vagrant installed on a Mac with Apple Silicon (ARM) |

VirtualBox is virtualization software that allows installing additional operating systems, known as “guest systems” or “virtual machines”, within your “host” system (in my case macOS), each with its own virtual environment. You can create virtual machines based on FreeBSD, GNU/Linux, OpenBSD, OS/2 Warp, Windows, Solaris, MS-DOS, Genode, and many others.

Vagrant lets you create and configure virtual development environments that are lightweight and reproducible, by creating virtual machines. It natively uses VirtualBox as its hypervisor.

We can install both to set up virtual Servers to accompany our software development.

Be sure to read the post Vagrant for Development.


HTTPie

I recommend the HTTPie tool if you’ll be working with APIs. It helps you work with your APIs in a simple and intuitive way. They have a graphical version and a CLI version.

The process to install it on Mac:

  • From the Downloads page, go to Download for MAC and install the GUI version

Examples:

  • Hello World
    • https httpie.io/hello
  • Custom HTTP method, HTTP headers, and JSON data
    • http PUT pie.dev/put X-API-Token:123 name=John
  • Form submission
    • http -f POST pie.dev/post hello=World
  • View the request being sent using one of the output options
    • http -v pie.dev/get
  • Build and print a request without sending it using offline mode
    • http --offline pie.dev/post hello=offline
  • Use the GitHub API to post a comment on an issue with authentication
    • http -a USERNAME POST https://api.github.com/repos/httpie/cli/issues/83/comments body=HTTPie is awesome! :heart:
  • Upload a file using redirected input
    • http pie.dev/post < files/data.json
  • Download a file and save it via redirected output
    • http pie.dev/image/png > image.png
  • Download a file wget-style
    • http --download pie.dev/image/png
  • Use named sessions to persist certain aspects of communication between requests to the same host
    • http --session=logged-in -a username:password pie.dev/get API-Key:123
    • http --session=logged-in pie.dev/headers
  • Set a custom host header to work around missing DNS records
    • http localhost:8000 Host:example.com

Others

Here’s a list of programs I usually install on my laptop. You can install several at once, putting more than one on the command line (separated by spaces).

Installation:

brew install <program(s)>
ProgramDescription
ffmpegA complete, cross-platform solution for recording, converting, and streaming audio and video.
iperf3For network testing. The use case is creating TCP and UDP data streams and measuring network performance.
jqFilter, search, and pretty-print JSON output instead of a single line.
knockClient for “Port Knocking”, a technique for securing your server.

Maintenance

We usually forget to maintain what we install, so knowing how to do updates and repairs is important. I usually update periodically, at least once a month, even if I don’t install anything new. I check that everything is up to date. Programs not mentioned in this section update automatically from AppStore or their own GUI options.

Updates

brew update && brew upgrade            # Standard homebrew update

Repairs

brew update && brew update
brew doctor                # Homebrew self-diagnosis tool.
brew --version             # Check the version
brew list                  # See what's installed
brew cask list             # See what casks are installed
brew leaves                # Top-level installed (most useful)
gem cleanup && gem pristine --all  # Update homebrew when you need to repair problems with the gem command