Appendix A — AWS Braket Setup & Cost Guardrails
Do this once, early — before Term 1 · The Qubit's first hands-on code. Everything in this program runs on the free local simulator by default; you only need an AWS account when you progress to on-demand simulators (SV1/DM1/TN1) and QPUs in Term 5.
Learning Objectives
By the end of this appendix you will be able to:
- Install
amazon-braket-sdk-pythonand run a circuit on the local simulator with no AWS account. - Create and configure AWS credentials, choose a Braket-supported region, and enable the service.
- Set up an IAM identity with least-privilege Braket permissions.
- Explain Braket's pricing model and put cost guardrails (budgets, alarms, tags) in place.
- List available devices programmatically and read their properties.
1. Install the SDK (no AWS account needed)
amazon-braket-sdk requires Python 3.11 or greater. Always work inside a virtual environment.
# Create and activate an isolated environment
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install the SDK (pulls in braket-default-simulator, boto3, etc.)
pip install --upgrade pip
pip install amazon-braket-sdk
# Optional extras you will use later in the program:
pip install amazon-braket-pennylane-plugin # Term 5.6 (PennyLane integration)
pip install matplotlib networkx # plotting + graph problems (QAOA)Verify the install and run your first quantum circuit — a Bell state on the local simulator. This costs nothing and touches no AWS service:
# bell_local.py — runs entirely on your machine, free, no AWS account required.
from braket.circuits import Circuit
from braket.devices import LocalSimulator
# Build a 2-qubit Bell circuit: H on qubit 0, then CNOT(control=0, target=1).
bell = Circuit().h(0).cnot(0, 1)
print(bell) # ASCII circuit diagram
# The default LocalSimulator backend is the state-vector simulator ("braket_sv").
device = LocalSimulator()
result = device.run(bell, shots=1000).result()
# Expect roughly half "00" and half "11" — the signature of an entangled Bell state.
print(result.measurement_counts) # e.g. Counter({'11': 507, '00': 493})T : |0|1|
q0 : -H-C-
|
q1 : ---X-
Counter({'00': 503, '11': 497})✅ Checkpoint: if you see roughly-balanced
00/11counts and no01/10, your SDK works. You can complete all of Terms 0–4's hands-on code onLocalSimulatoralone.
Local simulator backends
LocalSimulator accepts a backend name; you will meet all three in this program:
| Constructor | Backend | Use it for |
|---|---|---|
LocalSimulator() or LocalSimulator("braket_sv") |
State vector | Noiseless circuits (Terms 2–3). |
LocalSimulator("braket_dm") |
Density matrix | Noisy circuits (Term 4). |
LocalSimulator("braket_ahs") |
Analog Hamiltonian | Neutral-atom analog programs (Term 4.4 / 5). |
2. AWS Account & Credentials (needed for cloud devices only)
You only need this section when you reach Term 5 (or want to run SV1/DM1/TN1/QPUs earlier). Local-simulator lessons need none of it.
2.1 Create an account and an IAM user
- Create an AWS account at https://aws.amazon.com/ (a payment method is required even for the free tier).
- Do not use your root account for day-to-day work. In the IAM console, create a user (or an IAM Identity Center user) for yourself.
- Attach a Braket policy. The AWS-managed
AmazonBraketFullAccesspolicy is the simplest starting point; it grants Braket actions plus the S3/CloudWatch/IAM-passrole permissions Braket needs to store results and run jobs. For least privilege in shared accounts, scope a custom policy down to specific device ARNs and a single results bucket.
2.2 Install and configure the AWS CLI
# macOS (Homebrew); see docs for other platforms
brew install awscli
# Configure a named profile with your IAM access key, secret, and a Braket region.
aws configure --profile braket
# AWS Access Key ID [None]: AKIA....
# AWS Secret Access Key [None]: ....
# Default region name [None]: us-east-1
# Default output format [None]: jsonThis writes ~/.aws/credentials and ~/.aws/config. The Braket SDK uses boto3, which picks
up these credentials automatically. To select your named profile in a session:
export AWS_PROFILE=braket # Windows: set AWS_PROFILE=braket🔐 Security: never hard-code keys in source. Prefer short-lived credentials via IAM Identity Center / SSO (
aws sso login) or, on EC2/SageMaker, an attached IAM role. Rotate keys regularly.
2.3 Regions
Braket is available in a subset of AWS regions, and specific devices are tied to specific
regions (a QPU offered in us-east-1 may not exist in eu-west-2). Pick a region that hosts the
device you need. Because availability changes, enumerate devices programmatically rather than
hard-coding (see §4). The on-demand simulators SV1/DM1/TN1 are offered in several regions.
2.4 Enable the service and run remotely
First-time use: open the Braket console and accept the terms to enable the service. Then the same Bell circuit on the on-demand state-vector simulator SV1 (⚠️ this one is billed — see §5):
# bell_sv1.py — ⚠️ INCURS AWS CHARGES (SV1 is a paid managed simulator).
from braket.aws import AwsDevice
from braket.devices import Devices
from braket.circuits import Circuit
bell = Circuit().h(0).cnot(0, 1)
# The Devices enum gives readable, current references to managed devices.
device = AwsDevice(Devices.Amazon.SV1) # equivalently AwsDevice(<SV1 ARN>)
# Managed/QPU runs are asynchronous: run() returns a task you poll for results.
task = device.run(bell, shots=1000)
print("Task ARN:", task.id) # also visible in the console
result = task.result() # blocks until the task completes
print(result.measurement_counts)Results are written to a default Amazon S3 bucket that Braket manages for you (
amazon-braket-<region>-<accountId>); you no longer need to pre-create or pass a bucket for basic runs. You can override the destination with thes3_destination_folderargument if your org requires a specific bucket.
3. Quotas, Tasks, and Asynchrony (mental model)
- A quantum task is one submission of a circuit (with a shot count) to a device.
- Local runs are synchronous and free. Managed runs (SV1/DM1/TN1/QPU) are asynchronous:
run()returns immediately with a task you later.result()on; results persist in S3. - QPUs run only during device-specific availability windows and may queue. Check a device's status and window in the console or via its properties (see §4) before submitting.
- Default result-polling timeout is 5 days; adjust with
poll_timeout_seconds.
4. Discovering Devices Programmatically
Never hard-code device ARNs from a tutorial — availability drifts. Ask the service:
# list_devices.py — read-only metadata calls; listing/searching devices is not billed.
from braket.aws import AwsDevice
# All ONLINE devices visible to your account/region (simulators + QPUs).
for dev in AwsDevice.get_devices(statuses=["ONLINE"]):
print(f"{dev.name:24s} type={dev.type:10s} arn={dev.arn}")
# Inspect a specific device's capabilities, native gates, connectivity, and shot limits.
from braket.devices import Devices
sv1 = AwsDevice(Devices.Amazon.SV1)
print(sv1.properties.action) # supported program/result types
print(sv1.status) # ONLINE / OFFLINE / RETIREDFor a QPU you will also inspect properties.paradigm (qubit count, connectivity graph),
properties.provider (calibration/fidelity data), and the device's execution window. We do this in
detail in Term 5.3 · Devices & Paradigms.
5. Cost Guardrails
This section is mandatory reading before you run anything outside LocalSimulator.
5.1 How Braket bills (the shape, not the prices)
Pricing changes; confirm current numbers on the Braket pricing page. The structure is stable:
| Resource | Billing shape |
|---|---|
LocalSimulator |
Free (runs on your machine). |
| On-demand simulators (SV1, DM1, TN1) | Per minute of simulation time (a small per-minute rate, billed by the millisecond, with a per-task minimum). Big circuits / many shots = more minutes. |
| QPUs | Per-shot fee plus a per-task fee. Cost scales with shots. A few thousand shots on a QPU is real money. |
| Hybrid Jobs | The above device costs plus the cost of the classical instance running your job. |
Implications for how you work in this program:
- Develop and debug on
LocalSimulator(free). Only promote to a managed device when the circuit is correct and you actually need it. - Treat
shotsas a budget knob. Don't run 100,000 shots on a QPU "to be safe." - TN1 is only economical for circuits with favorable tensor-network structure; SV1 for general circuits up to ~34 qubits; DM1 for noisy circuits up to ~17 qubits. (Limits are approximate and evolve — verify in the console.)
5.2 Put hard guardrails in place (do this now)
- AWS Budgets: create a monthly cost budget (e.g. $20) with email alerts at 50%/80%/100%. Console → Billing → Budgets → Create budget.
- CloudWatch billing alarm: add a billing-metric alarm as a second safety net.
- Cost allocation tags: tag every task/job (e.g.
Project=qc-degree) so you can attribute and filter spend in Cost Explorer:task = device.run(bell, shots=100, tags={"Project": "qc-degree", "Lesson": "appendixA"}) - Confirm before paid runs: keep a habit (and we enforce it in lessons) of a guard like:
import os ALLOW_PAID = os.environ.get("BRAKET_ALLOW_PAID") == "1" assert ALLOW_PAID, "Refusing to submit a paid task. Set BRAKET_ALLOW_PAID=1 to override."
⚠️ The single most common surprise bill is a large shot count on a QPU inside a loop (e.g. a variational optimizer calling the device hundreds of times). When you reach Term 5.5 · Hybrid Jobs, you will learn to estimate cost before launching such loops.
6. Optional: Braket-Hosted Notebooks
Amazon Braket offers managed Jupyter notebook instances (a SageMaker notebook with the SDK pre-installed). They are convenient but the notebook instance itself is billed while running — stop it when idle. For this self-paced program, a local virtual environment is the cheapest and recommended setup; use hosted notebooks only if you prefer not to manage Python locally.
Checkpoint
- Can you run the local Bell circuit and explain why only
00/11appear? - What are the three
LocalSimulatorbackends and when do you use each? - Which two cost components dominate a QPU task, and which knob most directly controls cost?
- Why should you enumerate devices with
AwsDevice.get_devices()instead of copying an ARN? - Name two guardrails you put in place before running any paid task.
Answers
- The Bell state is — the two qubits are
perfectly correlated, so measurement yields
00or11with ~50% each and never01/10. braket_sv(state vector, noiseless),braket_dm(density matrix, for noise),braket_ahs(analog Hamiltonian simulation for neutral-atom programs).- A per-shot fee and a per-task fee;
shotsmost directly controls cost. - Device availability and ARNs change over time and by region; querying the service avoids stale, broken, or region-mismatched ARNs.
- Any two of: an AWS Budget with alerts, a CloudWatch billing alarm, cost-allocation tags, and an
explicit
BRAKET_ALLOW_PAIDguard before submission.
Further Reading
- [AWS] Amazon Braket Developer Guide — Get started and Pricing sections: https://docs.aws.amazon.com/braket/
amazon-braket-sdk-pythonREADME & examples: https://github.com/amazon-braket/amazon-braket-sdk-python- Amazon Braket pricing: https://aws.amazon.com/braket/pricing/
← Back to Program Index · Next: Appendix B — Python/NumPy Refresher →