Skip to content
Home/Blog/Running Qiskit Circuits on Azure Quantum: A Practical Guide
QiskitHardwareBest Practices

Running Qiskit Circuits on Azure Quantum: A Practical Guide

How to submit Qiskit circuits to Azure Quantum hardware using the current qdk package: connecting to a workspace, listing targets, running on real hardware, handling qubit loss, and running locally on the QDK's sparse simulator without Azure at all.

FreeQuantumComputing
·· 7 min read

Azure Quantum gives Qiskit users access to hardware from multiple vendors, Rigetti, IonQ, and Quantinuum among them, through one workspace and one billing relationship. This walkthrough uses Microsoft's current Quantum Development Kit (QDK) package pattern, which replaced the older standalone azure-quantum package, covered as a migration note in our common Qiskit errors post if you're updating existing code.

pip install --upgrade "qdk[azure,qiskit]" ipykernel

Prerequisites

You need an Azure Quantum workspace already created in an Azure subscription, which is where billing, quotas, and provider access (which hardware vendors you've enabled) live. This guide assumes that workspace already exists. Setting one up happens through the Azure portal, not through Qiskit code.

Connecting to your workspace

from qdk.azure import Workspace

workspace = Workspace(resource_id="")  # your workspace's resource ID, from the Azure portal

The resource ID identifies your specific workspace and is found on its Overview page in the Azure portal. Nothing about this step is Qiskit-specific: it's the same connection object other language integrations (Cirq, Q#) use too.

Listing available targets

from qdk.azure.qiskit import AzureQuantumProvider

provider = AzureQuantumProvider(workspace)

for backend in provider.backends():
    print("- " + backend.name)

Only the targets enabled for your specific workspace show up here, which depends on which hardware providers you've added in the Azure portal, not on what Azure Quantum offers in general. A workspace with only Rigetti enabled won't list IonQ or Quantinuum targets, regardless of what's technically available on the platform.

Running a circuit

from qiskit import QuantumCircuit

circuit = QuantumCircuit(3, 3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0, 1, 2], [0, 1, 2])

backend = provider.get_backend("rigetti.sim.qvm")
job = backend.run(circuit, shots=1000)

result = job.result()
print(result.get_counts(circuit))

This targets Rigetti's simulator, a free target on most workspaces, useful for confirming your circuit and workspace connection both work before spending real budget on QPU time. Swap the backend name for a real QPU target (one of the names printed by provider.backends() above) once you're ready to run on hardware.

Handling qubit loss in results

Some hardware modalities lose a qubit mid-shot on occasion (an atom escaping an optical trap, for instance), and Azure Quantum's Qiskit results distinguish shots that completed cleanly from the raw total:

print("Counts:", result.results[0].data.counts)          # shots without qubit loss
print("Raw counts:", result.results[0].data.raw_counts)   # every shot, including lost ones

If counts and raw_counts differ, some fraction of your shots were dropped due to qubit loss during that run, worth checking on unfamiliar hardware before assuming your total shot count matches what you requested. For targets that don't experience qubit loss, the two are identical.

Estimating cost before running on real hardware

Real QPU targets bill per shot or per task depending on the provider, and both IonQ's and Quantinuum's pricing details live in the Azure Quantum documentation rather than in the SDK itself. Check current pricing, and your workspace's specific rate, in the Provider tab of your workspace in the Azure portal before submitting a real hardware job at any meaningful shot count, the same discipline worth applying to any pay-per-shot QPU access, Amazon Braket included.

Running locally without Azure at all

The QDK also ships a local simulator that needs no Azure connection or workspace, useful for iterating on circuit logic before you're ready to submit anything remotely:

from qsharp.interop.qiskit import QSharpBackend

backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()
print(counts)

This is a genuinely separate code path from the Azure-connected backend above, worth using during development specifically because it has zero cost and zero queue time, reserving the Azure-connected run for once real hardware or a provider-specific cloud simulator is what you need.

Try this next

  • Run the same circuit against rigetti.sim.qvm and the local QSharpBackend, and confirm the resulting counts distributions match within normal shot noise, a good sanity check that your circuit behaves consistently across both paths.
  • List your workspace's available targets and check queue times before submitting to real hardware, since a busy QPU target behaves like a stuck job the same way it does on IBM's free tier.
  • Compare this workflow against running Qiskit on IBM's own Runtime service if you're deciding between IBM-direct access and multi-vendor access through Azure Quantum.