Which framework should I use?

Short version: learning or general work, use Qiskit; quantum machine learning, use PennyLane; Google hardware, use Cirq; many cloud vendors at once, use Amazon Braket; optimization on annealers, use D-Wave Ocean. Choosing between the top two? See Qiskit vs PennyLane, or start with the learning roadmap.

Quick Comparison

Framework Primary use case Hardware access Differentiable Language Best for
Qiskit General purpose IBM Quantum (free) Via Qiskit Machine Learning Python Beginners, IBM hardware
Cirq Hardware research Google (research access) Partial Python Google hardware, low-level control
PennyLane QML / hybrid Any (plugin system) Yes (parameter-shift) Python Machine learning, research
Braket Cloud multi-hardware IonQ, Rigetti, QuEra, IQM No Python Production, AWS users
PyQuil Rigetti hardware Rigetti QCS No Python Rigetti hardware
tket Compilation / optimization Any (backend plugins) No Python / C++ Circuit optimization, hardware-agnostic
Q# Algorithms / research Azure Quantum No Q# (own lang) Microsoft ecosystem, resource estimation

Compare Syntax

Installation

Qiskit

pip install qiskit qiskit-aer qiskit-ibm-runtime

Cirq

pip install cirq

Braket

pip install amazon-braket-sdk amazon-braket-default-simulator

PyQuil

pip install pyquil

tket

pip install pytket pytket-qiskit

Q#

pip install qsharp

Bell State (H + CNOT)

Qiskit

from qiskit import QuantumCircuit

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

Cirq

import cirq

q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.measure(q0, q1, key='m'),
])

PennyLane

import pennylane as qml

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)
def bell():
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.probs(wires=[0, 1])

Braket

from braket.circuits import Circuit

circuit = Circuit().h(0).cnot(0, 1)

PyQuil

from pyquil import Program
from pyquil.gates import H, CNOT, MEASURE

p = Program()
ro = p.declare('ro', 'BIT', 2)
p += H(0)
p += CNOT(0, 1)
p += MEASURE(0, ro[0])
p += MEASURE(1, ro[1])

tket

from pytket import Circuit

circ = Circuit(2, 2)
circ.H(0)
circ.CX(0, 1)
circ.measure_all()

Q#

operation BellState() : (Result, Result) {
    use (q0, q1) = (Qubit(), Qubit());
    H(q0);
    CNOT(q0, q1);
    return (MResetZ(q0), MResetZ(q1));
}

Run & Get Measurement Counts

Qiskit

from qiskit_aer import AerSimulator
from qiskit import transpile

sim = AerSimulator()
result = sim.run(transpile(qc, sim), shots=1000).result()
print(result.get_counts())

Cirq

sim = cirq.Simulator()
result = sim.run(circuit, repetitions=1000)
print(result.histogram(key='m'))

PennyLane

# probs() returns exact distribution
# For shot-based counts:
@qml.qnode(dev, shots=1000)
def bell_shots():
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.counts(wires=[0, 1])

print(bell_shots())

Braket

from braket.devices import LocalSimulator

device = LocalSimulator()
result = device.run(circuit, shots=1000).result()
print(result.measurement_counts)

PyQuil

from pyquil import get_qc
from collections import Counter

p.wrap_in_numshots_loop(1000)
qc = get_qc('2q-qvm')
results = qc.run(p).readout_data.get('ro')
print(Counter(map(tuple, results)))

tket

from pytket.extensions.qiskit import AerBackend

backend = AerBackend()
compiled = backend.get_compiled_circuit(circ)
result = backend.run_circuit(compiled, n_shots=1000)
print(result.get_counts())

Q#

import qsharp

results = [qsharp.eval("""
    use (q0, q1) = (Qubit(), Qubit());
    H(q0); CNOT(q0, q1);
    let r = (M(q0), M(q1));
    ResetAll([q0, q1]); r
""") for _ in range(1000)]

from collections import Counter
print(Counter(results))

Parameterised Single-Qubit Rotation (Ry)

Qiskit

from qiskit.circuit import Parameter

theta = Parameter('theta')
qc = QuantumCircuit(1)
qc.ry(theta, 0)
bound = qc.assign_parameters({theta: 1.5708})

Cirq

import sympy

theta = sympy.Symbol('theta')
q = cirq.LineQubit(0)
circuit = cirq.Circuit(cirq.ry(theta)(q))

# Resolve
resolver = cirq.ParamResolver({'theta': 1.5708})
resolved = cirq.resolve_parameters(circuit, resolver)

PennyLane

import pennylane as qml
from pennylane import numpy as np

@qml.qnode(dev)
def rotation(theta):
    qml.RY(theta, wires=0)
    return qml.expval(qml.PauliZ(0))

# Also: gradient is free
grad = qml.grad(rotation)
print(grad(np.array(1.5708, requires_grad=True)))

Braket

from braket.circuits import Circuit, FreeParameter

theta = FreeParameter('theta')
circuit = Circuit().ry(0, theta)

result = device.run(
    circuit, shots=1000, inputs={'theta': 1.5708}
).result()

PyQuil

from pyquil import Program
from pyquil.gates import RY, MEASURE

p = Program()
angle = p.declare('angle', 'REAL', 1)
ro = p.declare('ro', 'BIT', 1)
p += RY(angle, 0)
p += MEASURE(0, ro[0])

qc = get_qc('1q-qvm')
result = qc.run(p, memory_map={'angle': [1.5708]})

tket

from pytket.circuit import fresh_symbol
import sympy

theta = fresh_symbol('theta')
circ = Circuit(1)
circ.Ry(theta / sympy.pi, 0)   # tket angles in half-turns

circ.symbol_substitution({theta: 1.5708})

Q#

operation RotateY(theta : Double) : Result {
    use q = Qubit();
    Ry(theta, q);
    return MResetZ(q);
}

// From Python:
// qsharp.eval(f"RotateY({1.5708})")

Get the Statevector

Qiskit

from qiskit.quantum_info import Statevector

sv = Statevector(qc)
print(sv.data)
print(sv.probabilities_dict())

Cirq

sim = cirq.Simulator()
result = sim.simulate(circuit)
print(result.final_state_vector)

PennyLane

@qml.qnode(dev)
def get_state():
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.state()

print(get_state())

Braket

# shots=0 returns statevector
result = device.run(circuit, shots=0).result()
print(result.values[0])

PyQuil

from pyquil.api import WavefunctionSimulator

wfs = WavefunctionSimulator()
wf = wfs.wavefunction(p)
print(wf.amplitudes)
print(wf.probabilities())

tket

from pytket.extensions.qiskit import AerStateBackend

backend = AerStateBackend()
state = backend.run_circuit(circ).get_state()
print(state)

Q#

// DumpMachine prints statevector to stdout
import qsharp
qsharp.eval("""
    use q = Qubit();
    H(q);
    Microsoft.Quantum.Diagnostics.DumpMachine();
    Reset(q);
""")

Draw / Visualise the Circuit

Qiskit

print(qc.draw('text'))
qc.draw('mpl')     # matplotlib
qc.draw('latex')   # LaTeX

Cirq

print(circuit)
print(circuit.to_text_diagram())

PennyLane

print(qml.draw(bell)())
qml.draw_mpl(bell)()

Braket

print(circuit)
# ASCII diagram built-in

PyQuil

# PyQuil prints Quil assembly, not diagrams
print(p)
# Use qiskit to visualise via conversion

tket

from pytket.utils import Graph
Graph(circ).get_DAG()  # DAG view
# Or render via qiskit:
from pytket.extensions.qiskit import tk_to_qiskit
tk_to_qiskit(circ).draw('mpl')

Q#

// Q# has no built-in visualiser
// Export to Qiskit via pytket or
// use VS Code Azure Quantum extension
// for circuit preview in the IDE

Frequently asked questions

Which quantum computing framework is best?
There is no single best framework; it depends on your goal. Qiskit is best for learning and general-purpose work and gives free access to IBM hardware. PennyLane is best for quantum machine learning and differentiable circuits. Cirq is best for Google hardware and low-level control. Amazon Braket is best for accessing many hardware vendors through one cloud SDK. D-Wave Ocean is best for combinatorial optimization on quantum annealers. Most gate-model frameworks share the same core concepts, so skills transfer.
Qiskit vs Cirq vs PennyLane: what is the difference?
Qiskit (IBM) and Cirq (Google) are both general-purpose circuit frameworks; the main difference is which hardware ecosystem and level of control you want, with Qiskit being more beginner-friendly and Cirq giving finer low-level control. PennyLane (Xanadu) is different in kind: it specializes in differentiable programming for quantum machine learning and is backend-agnostic, running on IBM, Google, and Braket hardware through plugins. For a deeper head-to-head, see our Qiskit vs PennyLane guide.
What programming language do quantum frameworks use?
Most use Python: Qiskit, Cirq, PennyLane, Amazon Braket, PyQuil, tket, D-Wave Ocean, and Strawberry Fields are all Python libraries. The exceptions are Q#, which is Microsoft's own dedicated quantum language, and OpenQASM, which is a low-level assembly-like representation that other tools compile to rather than a general programming language.
Can I switch quantum frameworks later?
Yes. The core concepts (qubits, gates, measurement, superposition, entanglement) are the same across frameworks, so once you know one, picking up another takes days. Many frameworks also interoperate: PennyLane is backend-agnostic, Braket exposes multiple vendors, and tools can import or export OpenQASM. Starting with one framework does not lock you in.
Do I need a different framework for each quantum computer?
Not necessarily. Qiskit targets IBM hardware and Cirq targets Google hardware natively, but Amazon Braket gives one SDK across IonQ, Rigetti, IQM, and QuEra, and PennyLane runs the same code on many backends through plugins. You only need multiple frameworks if you want each vendor's native, lowest-level features.