brew install awscli installs AWS CLI v2 on macOS, puts aws on your PATH, and handles the Python dependency itself — which is the main reason to prefer it over pip.
The install is one command. The parts worth getting right are confirming you actually got v2, and configuring credentials in a way that does not leave long-lived access keys sitting in a plaintext file in your home directory for the next three years.
Table of contents
- The install
- Do not install it with pip
- When aws —version reports the wrong thing
- Configuring credentials without leaving keys lying around
- Shell completion
- The CLI is for your laptop, not your deploys
- How this fits the rest of the stack
- FAQ
The install
brew update
brew install awscli
brew update first is not ceremony — an out-of-date formula index installs an out-of-date CLI, and AWS ships changes to this tool constantly.
Verify:
aws --version
# aws-cli/2.x.x Python/3.x.x Darwin/23.x.x source/arm64
You want aws-cli/2 at the start. If it says aws-cli/1, you have the old major version from somewhere else on your PATH — see below.
To upgrade later:
brew upgrade awscli
Do not install it with pip
The AWS docs still mention pip install awscli, and it still works, and it is still the wrong choice on a machine you use for other Python work.
pip install awscli puts the CLI and its dependencies into whichever Python environment happens to be active. That pins botocore, urllib3, and several others to versions the CLI requires. Any project in that same environment now shares those pins. The failure mode is a dependency resolution error in an unrelated project weeks later, and the connection to the day you installed the AWS CLI is not obvious.
It also breaks in the other direction. Upgrade a package for a project and you can leave the CLI unable to import its own dependencies.
Homebrew’s formula bundles its own Python runtime, isolated from anything you use for development. The CLI upgrades on its own schedule and cannot interfere with your projects. That isolation is the entire argument, and it is enough.
If a pip-installed copy is already on your machine, remove it before installing through Homebrew:
pip uninstall awscli
brew install awscli
which aws # /opt/homebrew/bin/aws on Apple Silicon
When aws —version reports the wrong thing
Two copies on one machine is common, especially if you previously used the official pkg installer, which drops binaries in /usr/local/bin.
which -a aws
# /usr/local/bin/aws
# /opt/homebrew/bin/aws
Whichever appears first in PATH wins. On Apple Silicon, Homebrew lives at /opt/homebrew/bin, and if /usr/local/bin precedes it in your shell profile you will keep running the old copy no matter how many times you reinstall.
Either remove the stale copy:
sudo rm -rf /usr/local/aws-cli /usr/local/bin/aws /usr/local/bin/aws_completer
Or fix the ordering in ~/.zshrc so the Homebrew shims come first:
eval "$(/opt/homebrew/bin/brew shellenv)"
Then open a new shell — which -a aws in the same session will keep showing the cached lookup.
Configuring credentials without leaving keys lying around
The obvious next step is aws configure, which prompts for an access key and secret and writes them to ~/.aws/credentials in plaintext.
aws configure
# AWS Access Key ID [None]: AKIA...
# AWS Secret Access Key [None]: ...
# Default region name [None]: eu-west-1
# Default output format [None]: json
That is fine for a throwaway sandbox account. For anything attached to real infrastructure, those are long-lived credentials with no expiry sitting unencrypted on a laptop, and laptops get stolen, backed up to places you forgot about, and shared over screen-sharing calls.
The better default is SSO, which issues short-lived credentials that expire on their own:
aws configure sso
# SSO session name: my-org
# SSO start URL: https://my-org.awsapps.com/start
# SSO region: eu-west-1
aws sso login --profile dev
aws s3 ls --profile dev
Nothing permanent is written to disk. When the session expires you run aws sso login again. If the laptop is lost, the credentials on it are already dead or die within hours.
Use named profiles either way, and set the profile per-shell rather than making the powerful one your default:
export AWS_PROFILE=dev
aws sts get-caller-identity # confirm who you are before doing anything
aws sts get-caller-identity before a destructive command is a two-second habit that has saved a lot of people from running the right command against the wrong account.
Shell completion
Homebrew installs the completer but does not wire it up. For zsh, which is the macOS default:
# ~/.zshrc
autoload -Uz compinit && compinit
complete -C "$(brew --prefix)/bin/aws_completer" aws
Reload the shell and aws s3 <tab> starts completing subcommands. Given how many services and flags this CLI carries, that is a genuine reduction in documentation lookups.
The CLI is for your laptop, not your deploys
A working local CLI has a way of turning into a deployment process. Someone builds locally, runs a sync command, and the site is live. It works, right up until it is the only way anything ships and only one person’s machine is configured to do it.
That setup has no build log, no record of what was deployed, no rollback, and a hard dependency on credentials living on a specific laptop. When that person is away and something needs fixing, nobody else can ship.
Deployment belongs to a pipeline that runs from the repository — the same build every time, logs you can read afterwards, secrets held by the platform rather than by a person, and a previous version to roll back to. On RunxBuild that is connecting the repository and pushing; the build runs on the platform, the route goes live, and the deploy log stays available when someone asks what changed.
Keep the CLI for what it is genuinely good at: inspecting resources, poking at buckets, and answering questions interactively.
How this fits the rest of the stack
Local tooling is free. The infrastructure it points at is not, and cloud line items are famously easier to add than to remove. The RunxBuild hosting calculator puts compute, database, storage, and bandwidth on one page so the total is visible before you commit to it.
Useful related references:
- GCP vs AWS: Pricing, Network, and When to Pick Each
- Decentralized Computing vs Cloud Computing: AWS/GCP vs DePIN
- Competitors for AWS: GCP, Azure, and the Smaller Clouds
- Python services on RunxBuild
FAQ
How do I install the AWS CLI on macOS with Homebrew?
Run brew update then brew install awscli. Verify with aws —version, which should report aws-cli/2 at the start. Upgrade later with brew upgrade awscli.
Should I use brew or pip to install the AWS CLI?
Homebrew. pip install awscli places the CLI into whichever Python environment is active and pins shared dependencies like botocore and urllib3, which breaks unrelated projects later. The Homebrew formula bundles its own isolated Python runtime.
Why does aws —version show version 1 after installing with brew?
Another copy is earlier in your PATH, usually from the official pkg installer in /usr/local/bin. Run which -a aws to see every copy, then either remove the stale one or make sure the Homebrew path comes first in your shell profile. Open a new shell afterwards.
Is aws configure safe to use?
It writes long-lived access keys in plaintext to ~/.aws/credentials, which is acceptable for a sandbox account and risky for anything real. Prefer aws configure sso, which issues short-lived credentials that expire automatically and leaves nothing permanent on disk.
How do I enable AWS CLI tab completion in zsh?
Add autoload -Uz compinit && compinit and complete -C ”$(brew —prefix)/bin/aws_completer” aws to ~/.zshrc, then reload the shell. Homebrew installs the completer binary but does not register it.