Using Multiple AWS Accounts on One Computer
Managing more than one AWS account from one computer is a daily need for both software engineers and DevOps — a development account for experiments, staging for testing before releases, production for live systems, or even separate client accounts. Without neat configuration, the biggest risk is real: running destructive commands on the wrong account, for example deleting production resources when you meant staging. AWS CLI provides a profile mechanism to handle this, but just knowing how to create profiles isn’t enough — the part that’s often missed is how to make sure the active profile is truly the one you intend before a command executes. This article discusses AWS CLI profiles thoroughly, from file structure to work habits that prevent fatal mistakes.
AWS Profile Basics
AWS CLI stores configuration in two separate files, and understanding why they’re separated helps avoid confusion when troubleshooting later:
~/.aws/credentials— stores the Access Key and Secret Key, data that’s confidential~/.aws/config— stores region, output format, and additional settings, data that isn’t confidential
This separation isn’t a coincidence. Credentials are something very sensitive and ideally managed differently from regular settings like region — some teams even separate file system permissions at the OS level between these two files. With profiles, you store many sets of credentials at once on the same computer, then choose which account is active when running a particular command.
flowchart TD
A[aws CLI command] --> B{Which profile is active?}
B --> C[Read ~/.aws/credentials]
B --> D[Read ~/.aws/config]
C --> E[Access Key + Secret Key for this profile]
D --> F[Region + output format for this profile]
E --> G[Request to AWS API]
F --> GThe credentials File Structure
The ~/.aws/credentials file uses the INI format, with each [profile_name] block representing one account. Suppose you manage three accounts: default, staging, and production.
[default]
aws_access_key_id = AKIADEFAULTEXAMPLE
aws_secret_access_key = secretdefaultkey
[staging]
aws_access_key_id = AKIASTAGINGEXAMPLE
aws_secret_access_key = secretstagingkey
[production]
aws_access_key_id = AKIAPRODEXAMPLE
aws_secret_access_key = secretproductionkey
Several important things about this structure:
- The
[default]block is used automatically if no other profile is explicitly specified — this means a command without any profile flag falls back to this account - Profiles other than
defaultare only active when explicitly called, via a flag or environment variable - Profile names in the
credentialsfile are written plainly without any prefix:[staging], not[profile staging]
Never put production account credentials as[default]. If one day you run a command and forget to specify a profile without realizing it, that command automatically falls back todefault— and if that’s production, a small mistake can be fatal.
The config File Structure
The ~/.aws/config file stores non-secret settings like region and output format per profile. The structure is similar, but there’s one crucial difference that’s often a source of confusion for new developers.
[default]
region = us-west-2
output = json
[profile staging]
region = us-east-1
output = json
[profile production]
region = ap-southeast-1
output = json
Look closely: in the config file, every profile other than default must be prefixed with the word profile inside the square brackets — [profile staging], not [staging]. This is the opposite of the credentials file, which uses no prefix at all.
flowchart LR
subgraph credentials [~/.aws/credentials]
A1["[default]"]
A2["[staging]"]
A3["[production]"]
end
subgraph config [~/.aws/config]
B1["[default]"]
B2["[profile staging]"]
B3["[profile production]"]
endForgetting to add theprofileprefix in theconfigfile is the most common mistake when setting up multi-account for the first time. The result is that AWS CLI can still authenticate (because the credentials are valid), but the region or output settings for that profile are never read — often appearing as a confusing region error even though the credentials are correct.
Activating a Profile
There are two main ways to determine which profile is active for a command, and both can overlap if used together.
The --profile Flag per Command
The most explicit way — the profile only applies to that single command, without affecting other commands in the same terminal session.
aws s3 ls --profile staging
aws iam list-users --profile production
The AWS_PROFILE Environment Variable
The more practical way if you’ll run many commands in sequence on the same account — set it once, all subsequent commands automatically use that profile until the terminal session closes or it’s changed again.
# macOS / Linux
export AWS_PROFILE=staging
# Windows PowerShell
$Env:AWS_PROFILE="staging"
After this env var is set, all AWS CLI commands in the same terminal session automatically use the staging account without needing to repeat the --profile flag every time.
Precedence Between the Two
If AWS_PROFILE is already set as an env var but you also add the --profile flag to a particular command, the flag always wins for that command alone — the env var doesn’t change, only that command uses a different profile momentarily.
flowchart TD
A[aws command run] --> B{Has a --profile flag?}
B -- Yes --> C[Use the profile from the flag]
B -- No --> D{AWS_PROFILE set?}
D -- Yes --> E[Use the profile from the env var]
D -- No --> F[Use default]You can’t run two active profiles at once in a single command. A profile must be specified per command via the flag, or via an environment variable applying to the whole terminal session — there’s no “multi-profile” mechanism in one execution.
Verifying the Active Profile Before Execution
This is the part most often skipped, even though it’s the most important for preventing the “wrong account” risk mentioned at the start. Knowing how to activate a profile isn’t enough — you also need the habit of verifying which profile is currently active, especially before running destructive commands (delete, terminate, remove-stack, and similar).
The aws sts get-caller-identity command shows the identity of the account currently active based on the credentials being used:
aws sts get-caller-identity --profile production
{
"UserId": "AIDAEXAMPLE",
"Account": "111122223333",
"Arn": "arn:aws:iam::111122223333:user/budi"
}
The Account field here is the most reliable source of truth — not an assumption from the profile name you remember, but the real account ID returned by AWS. Make this a mandatory step before high-risk commands:
# Safe habit before destructive commands
aws sts get-caller-identity --profile production
# Check the Account ID output matches expectations, then continue:
aws cloudformation delete-stack --stack-name legacy-app --profile production
Consider creating a simple shell alias likewhoami-awsthat runsaws sts get-caller-identitywith the currently active profile. This small habit is far cheaper than the cost of recovering accidentally deleted production resources.
Using Profiles in Application Code
Profiles aren’t only used directly through AWS CLI — SDKs in various languages also support the same profile selection, reading from the exact same credentials and config files.
Node.js
const AWS = require('aws-sdk');
const credentials = new AWS.SharedIniFileCredentials({
profile: 'staging',
});
AWS.config.credentials = credentials;
const s3 = new AWS.S3();
Go
package main
import (
"context"
"log"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func main() {
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithSharedConfigProfile("staging"),
)
if err != nil {
log.Fatal(err)
}
client := s3.NewFromConfig(cfg)
_ = client
}
Python (boto3)
import boto3
session = boto3.Session(profile_name='staging')
s3 = session.client('s3')
The pattern in all three languages is the same: you don’t copy the Access Key and Secret Key directly into code, but refer to a profile name already configured in the credentials file. This aligns with the principle of avoiding hardcoded credentials — the SDK takes over reading the config file, and the application code only needs to know which profile name is used.
Don’t commit a production account profile name as a hardcoded default in application code shared across many environments. If the same code runs on another developer’s local development machine, they could accidentally access the production account because that profile exists on their computer with the same name.
Managing Profiles with Other Tools
Besides AWS CLI and application SDKs, infrastructure tools like Terraform also follow the same profile mechanism, because underneath they still read the standard ~/.aws/credentials and ~/.aws/config files.
provider "aws" {
region = "ap-southeast-1"
profile = "staging"
}
Or via the same environment variable as AWS CLI:
export AWS_PROFILE=staging
terraform plan
For projects handling many environments at once, some teams use tools like direnv to automatically set the matching AWS_PROFILE when entering a particular project directory — so the active profile is always consistent with the project being worked on, without needing to remember to export it manually every time you switch terminals.
# .envrc in the staging project directory
export AWS_PROFILE=staging
Safe Practices to Prevent Using the Wrong Account
The profile mechanism itself doesn’t automatically prevent mistakes — it only provides the means. The work habits around it are what actually determine how safe a multi-account setup is in practice.
Use consistent, unambiguous profile names. Naming like dev, staging, prod is far safer than names relying on memory, like account1 or new-client-a. Naming consistency across team members also reduces miscommunication risk when coordinating.
Show the active profile in the shell prompt. Many shell configurations (zsh, bash with plugins) can display the AWS_PROFILE value directly in the terminal prompt, so you always see which profile is active without checking manually every time.
Verify before destructive commands, not after. As discussed in the previous section, aws sts get-caller-identity before commands that delete or modify resources should be a habit, not an optional step.
Avoid storing production credentials on the same machine as daily access. If possible, limit who has production credentials stored locally — the fewer computers storing them, the smaller the surface of leak or mistake risk.
flowchart TD
A[Start a work session] --> B[Set AWS_PROFILE according to the project]
B --> C[Check the shell prompt shows the active profile]
C --> D{Destructive command?}
D -- Yes --> E[Run sts get-caller-identity]
E --> F{Account ID matches expectations?}
F -- Yes --> G[Continue the command]
F -- No --> H[STOP - switch the profile first]
D -- No --> GSummary Table
| Aspect | credentials file | config file |
|---|---|---|
| Contents | Access Key, Secret Key | Region, output format |
| Data nature | Confidential | Not confidential |
| Profile name format | [name] | [profile name] (except default) |
| Default profile | [default] | [default] |
| Activation Method | Scope | When Used |
|---|---|---|
--profile flag | A single command | Occasionally switching accounts, not wanting to change env vars |
AWS_PROFILE env var | The whole terminal session | Working consecutively on one same account |
direnv per directory | Automatically per project | Many projects with different accounts |
Summary
- AWS CLI stores credentials in
~/.aws/credentialsand non-secret settings in~/.aws/config— two files with different purposes.- Profile names in
credentialsare written plainly ([staging]), while inconfigthey must be prefixed withprofile([profile staging]) except fordefault.- The
defaultprofile activates automatically if none is specified — never put production credentials there.- Activate a profile via the
--profileflag for one-time use, or theAWS_PROFILEenv var for the whole terminal session; the flag always wins when both are used together.aws sts get-caller-identityis the most reliable way to verify which account is truly active — make it a mandatory habit before destructive commands.- SDKs in Node.js, Go, and Python all support the same profile selection, reading the same standard config files as AWS CLI.
- Tools like Terraform follow the same profile mechanism;
direnvcan help automate profiles per project directory.- Consistent profile naming, an active profile visible in the shell prompt, and verification before risky commands are the habits that truly prevent mistakes — not just the technical mechanism alone.