Skip to content

Setup Macbook M1 for Web and React Native development

Published:

10 min read

Note: A new version of this post was written in 2024. See My 2024 Macbook setup for more information.

🕑 This article was originally written on March 14, 2021. Since then, it has been updated many times to reflect my setup process. In 2023, I decided to re-write this article from scratch.

cover_image

It’s 2023, and I am still coming back to this article. I wrote this originally in 2021 to keep track of what I need to start when setting up a new laptop. Since then, I have had two Macbook Pros using an Apple Silicon processor (M1). I try to keep this article up to date.

I believe small optimizations help you go faster in the long run. Also, a flavor of personalization makes my developer experience more enjoyable. I like to keep two separate setups, one for work and the other for personal use and fun. However, often I end up switching between both. Having the same set of tools and configurations helps me just be me. It also helps me keep my setup portable and up-to-date (have had those days where I lost everything).

1: Install Xcode and Command Line Tools

To get started, open the App Store on the Mac and install Xcode. It’s a large download, so it might take a while.

Once installed, open the Terminal app on the Mac and run:

xcode-select --install && sudo xcodebuild -license

1.1: Verify Command Line Tools installation

After installing Xcode and command line tools, open the app. Then, from the menu bar, open Xcode > Preferences > Locations and make sure that Command Line Tools point towards the current Xcode app.

ss3

2: Install Warp terminal

Previously, I’ve used iTerm2 as y default terminal app over the years. Find more info about iterm2 in the Alternate tools section at the end of this post.

I recently started using Warp as my first choice for a terminal app on Mac. After downloading the app, start the app:

2.1: Install Oh My Zsh

ZSH is the default shell in macOS. However, I like to use Oh My Zsh to manage the ZSH configuration, plugins, and a theme to prettify the terminal (especially when using iterm2 previously).

To install, run the command below:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

After installation, make sure that the file .zshrc is exporting the below path at the top:

# Path to your oh-my-zsh installation
export ZSH="$HOME/.oh-my-zsh"

The $HOME should be /Users/<your-macos-username>. You can verify this by running:

echo $HOME

2.2: Install syntax highlighting plugin

The first I like to do after setting up the bare minimum ZSH configuration is to install a plugin called zsh-syntax-highlighting. It provides syntax highlighting for the ZSH shell. Execute the series below commands in the terminal window:

# depending on the /plugins folder in your local setup
cd $HOME/.oh-my-zsh/plugins

# then clone the git repository
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git

echo "source ${(q-)PWD}/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" >> ${ZDOTDIR:-$HOME}/.zshrc

On iterm2, after installing the syntax highlight plugin, it starts to recognize the commands:

ss4

Only for iterm2: Install a theme

The next step is to install spaceship-prompt theme. Follow the steps described in oh-my-sh section.

Final ZSH configuration

This is my final ZSH configuration in the file ~/.zshrc file:

# Path to your oh-my-zsh installation
export ZSH="/Users/amanhimself/.oh-my-zsh"

export PATH=/opt/homebrew/bin:$PATH

export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools

# ZSH_THEME="spaceship"

# Uncomment the following line to disable bi-weekly auto-update checks.
DISABLE_AUTO_UPDATE="true"

plugins=(
  git
  node
  vscode
  zsh-syntax-highlighting
)

source $ZSH/oh-my-zsh.sh
source /Users/amanhimself/.oh-my-zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

3: Change system settings

System preferences and settings that I prefer. These settings are available in the Systems Settings:

4: Install homebrew

On December 1, 2020, the Homebrew team announced on their website about the version release 2.6.0. The most significant changes they listed were:

Using the terminal, you can install the Homebrew by executing the default command:

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

5: Install Git

To install Git, run the command:

brew install git

To authenticate GitHub to be used from the terminal environment, I recommend you check out the official document on creating and accessing personal tokens.

🔥 Tip: As of Git version 2.28, there is a new config option to set the default branch to main. Set it globally and forget about it.

git config --global init.defaultBranch main

To enable colors in the output, run the command:

git config --global color.ui auto

6: Install homebrew packages

Run the following script to install other packages from homebrew:

brew install yarn
brew install scrcpy
brew install watchman
brew install exa
brew install imageoptim

Some highlights from the above script:

7: After installing Node.js

Node.js comes with the default package manager npm. Set defaults for it:

npm config set init-author-name "your name"
npm config set init-author-url "example.com"
npm config set init-license MIT

8: Install global npm packages

npm i -g eas-cli

Also, I use the following command to update global packages:

npx npm-check -gu

9: VS Code

VS Code and VS Code Insiders are currently supported on ARM chips (March 13, 2021). Download the installer for Insiders edition from here and for VS Code here.

ss5

I am using the following VS Code configuration:

{
  "workbench.startupEditor": "welcomePage",
  "workbench.iconTheme": "material-icon-theme",
  "workbench.editor.tabSizing": "shrink",
  "security.workspace.trust.untrustedFiles": "open",
  "explorer.confirmDelete": false,
  "explorer.confirmDragAndDrop": false,
  "workbench.editor.enablePreview": false,
  "window.restoreFullscreen": true,
  "editor.tabSize": 2,
  "editor.fontSize": 13.5,
  "editor.minimap.enabled": false,
  "editor.cursorBlinking": "phase",
  "editor.fontLigatures": false,
  "editor.wordWrap": "on",
  "editor.cursorSmoothCaretAnimation": "on",
  "editor.tabCompletion": "on",
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "editor.semanticHighlighting.enabled": true,
  "editor.guides.bracketPairs": true,
  "explorer.openEditors.visible": 0,
  "files.trimTrailingWhitespace": true,
  "search.exclude": {
    "**/node_modules": true,
    "**/*.code-search": true,
    "dist/": true,
    "yarn.lock": true,
    "package-lock.json": true,
    ".gitignore": true,
    ".expo": true,
    ".vscode": true
  },
  "extensions.autoUpdate": false,
  // --------------------------------------
  // --------------------------------------
  // CODE::STATS EXTENSION
  // --------------------------------------
  // READ TIME EXTENSION
  "readTime.enabled": true,
  // --------------------------------------
  // HIGHLIGHT MATCHING TAG EXTENSION
  "highlight-matching-tag.styles": {
    "opening": {
      "name": {
        // surround is border
        "surround": "yellow"
      }
    }
  },
  // --------------------------------------
  // INTEGRATED TERMINAL
  "terminal.external.osxExec": "iTerm.app",
  // "terminal.external.osxExec": "warp.app",
  "terminal.integrated.fontSize": 12,
  // --------------------------------------
  // NPM
  "npm-intellisense.importES6": true,
  // --------------------------------------
  // TS IMPORT SUGGESTION
  "typescript.suggest.paths": false,
  // --------------------------------------
  // NATIVE BRACKET PAIR COLOR SETTINGS
  "editor.bracketPairColorization.enabled": true,
  "workbench.colorCustomizations": {
    "editorBracketHighlight.foreground1": "#ffb86c",
    "editorBracketHighlight.unexpectedBracket.foreground": "#ff5555",
    "[morgan.codes]": {
      "gitDecoration.ignoredResourceForeground": "#434343"
    },
    "[Expo Dark]": {
      // "activityBar.background": "#635985",
      "activityBarBadge.background": "#fc4384",
      "activityBarBadge.foreground": "#ffffff",
      // "activityBar.activeBackground": "#bd93f9",
      "activityBar.activeBorder": "#fc4384",
      "gitDecoration.ignoredResourceForeground": "#434343",
      "statusBar.background": "#fc4384",
      "statusBar.noFolderBackground": "#fc4384",
      // Gutter
      "editorGutter.deletedBackground": "#ff0055",
      "editorGutter.addedBackground": "#fc4384",
      "editorGutter.modifiedBackground": "#9765c9",

      // Selection and matches
      "editor.selectionHighlightBorder": "#e18cc9",
      "editor.selectionHighlightBackground": "#635985",
      "editor.selectionForeground": "#eff8ff",
      "editor.findMatchHighlightBackground": "#ff2b7c8e",
      "editor.hoverHighlightBackground": "#ff000013",
      "editor.lineHighlightBackground": "#2b2b2b50",
      "editor.lineHighlightBorder": "#00000000",
      "editorOverviewRuler.bracketMatchForeground": "#635985"
    }
  },
  // --------------------------------------
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  // Markdown
  "[markdown]": {
    "editor.quickSuggestions": {
      "comments": "on",
      "strings": "on",
      "other": "on"
    }
  },
  // JSON
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // JavaScript
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // JavaScript + React
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // TypeScript
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // TypeScript + React
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // JSON with Comments
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // HTML
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  // ----------------------------------
  // ESLINT
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
  ],
  // --------------------------------------
  // ERROR LENS
  // "errorLens.fontSize": "11",
  // "errorLens.onSave": true,
  // "errorLens.enabledDiagnosticLevels": ["error", "warning", "hint"],
  // "workbench.colorCustomizations": {
  //   "errorLens.hintForeground": "#ffc600A1",
  //   "errorLens.hintBackground": "#ff00dd2f",
  //   "errorLens.errorBackground": "#ff000005",
  //   "editor.selectionBackground": "#ff1493",
  //   "editor.selectionHighlightBackground": "#ff1493",
  //   "editor.findMatchBackground": "#ff1493",
  //   "editor.findMatchHighlightBackground": "#3cb371"
  // },
  // "errorLens.exclude": ["never (read|used)"],
  // --------------------------------------
  // LANGUAGES SPECIFIC
  "javascript.updateImportsOnFileMove.enabled": "always",
  "security.workspace.trust.banner": "never",
  "emmet.includeLanguages": {
    "typescript": "typescriptreact",
    "javascript": "javascriptreact"
  },
  "cSpell.userWords": [
    "Appbar",
    "asyncstorage",
    "backgrounded",
    "backoff",
    "Cacheable",
    "cancelation",
    "Chakra",
    "concurrencies",
    "Contentful",
    "Ecommerce",
    "Entypo",
    "Firestore",
    "Grammarly",
    "Ionicons",
    "launchable",
    "nocheck",
    "Parens",
    "Podfile",
    "prefetch",
    "Pressable",
    "Transifex",
    "Turborepo",
    "undeployed",
    "Vercel",
    "vercelians",
    "yantramanav",
    "zustand"
  ],
  "git.autofetch": true,
  "cSpell.language": "en,en-US",
  "cSpell.enableFiletypes": ["markdown", "mdx"],
  "editor.inlineSuggest.enabled": true,
  "github.copilot.enable": {
    "*": true,
    "yaml": true,
    "plaintext": true,
    "markdown": true
  },
  "workbench.colorTheme": "Expo Light",
  "window.commandCenter": true,
  "customizeUI.fontSizeMap": {
    "13px": "12px",
    "12px": "11px",
    "window-title": "12px", // Window title font when using custom titlebar
    "tab-title": "12px", // Used for editor tab titles
    "monospace": "11px" // Used for monospace fonts in user interface
  },
  "react-native-tools.showUserTips": false,
  "errorLens.fontSize": "12",
  "grammarly.files.include": [
    "**/README.md",
    "**/readme.md",
    "**/*.txt",
    "**/*.md",
    "**/*.mdx"
  ],
  "css.lint.unknownAtRules": "ignore",
  "workbench.editorAssociations": {
    "*.js": "default"
  },
  "githubPullRequests.pullBranch": "never"

VS Code themes

I usually like to switch between a dark and a light theme.

For a light theme, I prefer:

For the dark theme where I spent most of my time with fairyFloss.

For file icons, I love Material-Icon-Theme.

VS Code extensions

Apps

10: Download browsers

Use Safari for personal email.

Other apps on my macOS

Chrome settings

ImageOptim settings

The custom config I use for ImageOptim app:

General settings in ImageOptim

Quality settings in ImageOptim

Optimization settings in ImageOptim

Copy dotfiles

For React Native Development

Follow React Native documentation for info on how to install open JDK and Android Studio.

Alternate tools

Tools and apps that I’ve used in the past that I may come back to one day.

iterm2

My favorite terminal app that I have been using for years is iTerm2.

iterm1

iterm2

iterm3

Rosetta 2

Update: I am not using the Rosetta environment to install anything on the secondary machine since August 2021. That is why I’ve mentioned it at the end of the post.

Rosetta 2 is the lifeline that allows you to run apps designed for Intel-based chips that use x86 architecture on ARM-based chips (in this case M1). This solution is provided by Apple as an emulator and doesn’t come pre-installed. You have to install it manually. Fire up the Terminal application that comes pre-installed on the macOS and execute the following command:

/usr/sbin/softwareupdate --install-rosetta --agree-to-license

If you decide not to put the flag --agree-to-license, you will be prompted by Apple’s interactive install, and you will have to agree to their terms and license conditions to use it.

Conclusion

That’s the setup I now use for my JavaScript, Node.js, React, React Native and documentation work. I think it’s a great machine. Hopefully, M1 is just the beginning of a new era of powerful computers for daily work use.

🤔 The only thing left for me is to find a way to transfer all laptop swag/stickers from my Macbook Air 2017 to Pro. I miss having them on this one.

isapplesiliconready.com is another helpful link I found to check what is compatible to work on Apple Silicon chips natively or using Rosetta or not optimized at all.


Previous Post
Bypass CORS to fetch files when working with localhost
Next Post
Set default location for images, files and attachments in Obsidian

I'm a software developer and technical writer. On this blog, I share my learnings about both fields. Recently, I have begun exploring other topics, so don't be surprised if you find something new here.

Currently, working as a documentation lead at Expo.