migration.md
355 lines · skills/qiskit/references/migration.md at 5f2bc03
Most marks come from matching words in the file, so treat them as pointers.
Migration to Qiskit 2.5 and Runtime 0.50
Cloud authentication, QPU, session, and batch snippets are illustrative and were not executed in this refresh. Local evidence is listed in sources.md. Use this guide when adapting code written for Qiskit 0.x, Qiskit 1.x, or early Qiskit Runtime releases.
Raw lines 1 to 5Runtime 0.50 client-side primitives
The top-level qiskit_ibm_runtime.SamplerV2/EstimatorV2 and their aliases are deprecated, not removed. Replace their imports with:
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import Estimator
from qiskit_ibm_runtime.options_models import SamplerOptions, EstimatorOptionsPUBs and result fields remain V2. The new implementations prepare and process Executor workloads locally. Recheck option defaults with finalize_options().model_dump(), keep ISA compilation and observable layout mapping, and test local noise-management behavior. Server dry_run=True returns mock values and does not establish circuit correctness.
Start with a Clean Environment
Do not upgrade an environment containing both old qiskit-terra and modern qiskit.
uv venv --python 3.13 .venv-qiskit-2
source .venv-qiskit-2/bin/activate
uv pip install \
"qiskit==2.5.2" \
"qiskit-ibm-runtime==0.50.0" \
"qiskit-aer==0.17.2"Run:
python scripts/check_environment.py --require-runtime --require-aerRaw lines 18 to 36High-Level API Map
| Legacy pattern | Qiskit 2.5 pattern |
|---|---|
Install qiskit-terra | Install qiskit |
from qiskit import Aer | from qiskit_aer import AerSimulator |
execute(circuit, backend) | V2 primitive, or provider-specific backend only when necessary |
QuantumInstance | Primitive implementation plus explicit transpilation |
qiskit.opflow | qiskit.quantum_info.SparsePauliOp and primitive PUBs |
circuit.bind_parameters(...) | circuit.assign_parameters(...), or pass values in PUBs |
V1 Sampler / Estimator | StatevectorSampler / StatevectorEstimator, Runtime client-side Sampler / Estimator (V2 API) |
| Parallel V1 input lists | One or more PUB tuples |
result.quasi_dists | result[i].data.<register>.get_counts() |
result.values | result[i].data.evs |
Runtime shared Options() | SamplerOptions, EstimatorOptions, dict, or .options.update() |
Primitive backend= / session= | Primitive mode= |
| Runtime auto-transpilation | Explicit backend-specific ISA circuit |
| Logical observable submitted unchanged | observable.apply_layout(isa_circuit.layout) |
backend.configuration() / .properties() | BackendV2 direct attributes and backend.target |
channel="ibm_quantum" | channel="ibm_quantum_platform" |
qiskit.pulse | IBM fractional gates for hardware; isolated legacy simulation for archived Dynamics |
QFT(...) blueprint class | QFTGate(...) or synth_qft_full(...) |
| Blueprint ansatz classes | Function constructors such as efficient_su2(...) |
instruction.c_if(...) | Structured circuit control flow such as if_test(...) |
Migrate V1 Sampler
Legacy shape:
# Legacy; do not use
# sampler = Sampler()
# result = sampler.run(circuits, parameter_values).result()
# quasi_distribution = result.quasi_dists[0]Current local V2:
from qiskit.primitives import StatevectorSampler
sampler = StatevectorSampler(seed=41)
pub_result = sampler.run(
[(measured_circuit, parameter_values)],
shots=1024,
).result()[0]
counts = pub_result.data.meas.get_counts(0)Key changes:
- measured shot data replace V1 quasi-distributions,
- output is organized by classical register,
- parameter sweeps retain array shape,
- a PUB contains one circuit and its parameter values.
Migrate V1 Estimator
Legacy shape:
# Legacy; do not use
# estimator = Estimator()
# result = estimator.run(circuits, observables, values).result()
# expectation_value = result.values[0]Current local V2:
from qiskit.primitives import StatevectorEstimator
estimator = StatevectorEstimator()
pub_result = estimator.run(
[(circuit, observable, parameter_values)]
).result()[0]
expectation_values = pub_result.data.evs
standard_deviations = pub_result.data.stdsRaw lines 94 to 118Migrate Runtime Execution
Legacy Runtime:
# Legacy; do not use
# options = Options()
# options.resilience_level = 2
# estimator = Estimator(session=session, options=options)Current Runtime:
from qiskit_ibm_runtime.executor_estimator import Estimator
estimator = Estimator(
mode=session,
options={"resilience_level": 2},
)Use current mode syntax:
sampler = Sampler(mode=backend)
sampler = Sampler(mode=batch)
sampler = Sampler(mode=session)The old backend= constructor keyword is unsupported. Use mode=backend for job mode or mode=session / mode=batch explicitly.
Migrate to ISA Circuits
Legacy Runtime examples often submitted logical circuits and relied on service-side transpilation. V2 Runtime requires ISA circuits:
from qiskit.transpiler import generate_preset_pass_manager
pass_manager = generate_preset_pass_manager(
backend=backend,
optimization_level=1,
seed_transpiler=41,
)
isa_circuit = pass_manager.run(logical_circuit)Estimator observables must follow the layout:
isa_observable = logical_observable.apply_layout(
isa_circuit.layout
)Failing to map observables can silently change the physical qubits being measured or produce a width error.
Raw lines 151 to 175Migrate BackendV1 Access
Legacy:
# Legacy; do not use
# basis_gates = backend.configuration().basis_gates
# coupling_map = backend.configuration().coupling_map
# properties = backend.properties()Current:
basis_operations = backend.operation_names
coupling_map = backend.coupling_map
target = backend.target
num_qubits = backend.num_qubitsQuery gate errors, durations, and qubit support through the Target entries. Do not combine a backend with manually copied basis and coupling data unless constructing a deliberately synthetic target.
Migrate IBM Account Configuration
The IBM Quantum Platform Classic channel is retired.
Current trusted-machine setup:
import os
from qiskit_ibm_runtime import QiskitRuntimeService
QiskitRuntimeService.save_account(
channel="ibm_quantum_platform",
token=os.environ["IBM_QUANTUM_API_KEY"],
instance=os.environ.get("IBM_QUANTUM_INSTANCE"),
set_as_default=True,
overwrite=True,
)Do not paste a key into source or a notebook. See setup.md.
Raw lines 198 to 218Migrate Pulse Code
qiskit.pulse was removed in Qiskit 2.0 without a drop-in replacement.
Choose based on intent:
- To execute supported continuous-angle one- and two-qubit rotations on IBM hardware, request a backend target with fractional gates.
- For historical driven-system models, Qiskit Dynamics is archived and no longer maintained (October 2025). Treat it as a separately pinned legacy dependency, not a current Qiskit 2.x pulse replacement; choose a maintained dynamics solver for new research.
- To keep a historical pulse workflow unchanged, isolate it in a legacy Qiskit 1.x environment only for archival reproducibility; do not mix it with Qiskit 2.x.
Do not copy pulse.build, ScheduleBlock, or pulse-drawer examples into Qiskit 2.x code.
QPY files containing ScheduleBlock objects cannot be loaded by Qiskit 2.x.
Migrate Circuit-Library Blueprints
Several mutable blueprint classes are deprecated in favor of eagerly built functions or gates:
from qiskit.circuit.library import (
QFTGate,
efficient_su2,
real_amplitudes,
zz_feature_map,
)
qft_gate = QFTGate(4)
ansatz = efficient_su2(4, reps=2)
real_ansatz = real_amplitudes(4, reps=2)
feature_map = zz_feature_map(4, reps=2)The old QFT class is deprecated as of 2.1 and scheduled for removal in 3.0.
Function constructors can differ in mutability and construction timing from blueprint classes. Test parameter order and circuit metadata after migration.
Raw lines 233 to 254Migrate Classical Conditions
Legacy per-instruction conditions were removed:
# Legacy; do not use
# circuit.x(0).c_if(classical_register, 1)Use structured control flow:
with circuit.if_test((classical_bit, True)):
circuit.x(0)Then verify that the selected backend target supports the corresponding control-flow instruction.
Raw lines 255 to 272Migrate Qiskit Algorithms
Old quantum_instance= constructors are not current.
from qiskit.primitives import StatevectorSampler
from qiskit_algorithms import PhaseEstimation
phase_estimation = PhaseEstimation(
num_evaluation_qubits=4,
sampler=StatevectorSampler(seed=41),
)Current VQE takes a V2 Estimator; current QAOA takes a V2 Sampler.
Use optimizer objects:
from qiskit_algorithms.optimizers import COBYLA
optimizer = COBYLA(maxiter=100)Do not use strings such as optimizer="COBYLA" unless a specific current package API documents that form.
Migrate Qiskit Machine Learning
Since Qiskit Machine Learning 0.8, several features moved out of qiskit_algorithms:
# Current package locations
from qiskit_machine_learning.optimizers import COBYLA
from qiskit_machine_learning.state_fidelities import ComputeUncompute
from qiskit_machine_learning.utils import algorithm_globalsCheck the package's 0.8 migration guide for gradients, optimizers, fidelities, and utilities. Do not assume an import path from a Qiskit Machine Learning 0.7 tutorial still works.
Raw lines 299 to 311Migrate Qiskit Optimization 0.7
Use qiskit_optimization.minimum_eigensolvers.QAOA, qiskit_optimization.optimizers, and qiskit_optimization.utils.algorithm_globals with MinimumEigenOptimizer. Its result handling uses the package's own eigensolver/result classes. The stand-alone Algorithms package remains separate.
Migrate Qiskit Nature
Use mapper classes directly:
from qiskit_nature.second_q.mappers import JordanWignerMapper
mapper = JordanWignerMapper()
qubit_operator = mapper.map(fermionic_operator)QubitConverter is obsolete. Current application code lives primarily under qiskit_nature.second_q.
Serialization Migration
Prefer:
- QPY for Qiskit-native circuit persistence,
- OpenQASM for supported interchange,
- explicit JSON-compatible experiment metadata.
Avoid Python pickle for untrusted artifacts. QPY is forward-compatible but not backward-compatible: newer Qiskit normally reads older QPY, not vice versa.
Record the Qiskit version that wrote each QPY file.
Raw lines 329 to 340Migration Validation
After each migration:
- Run imports with deprecation warnings visible.
- Compare a small logical circuit's ideal state or operator.
- Verify parameter order and PUB output shape.
- Verify count-string and Pauli-label ordering.
- Compile against a fake
BackendV2. - Confirm all Estimator observables use the compiled layout.
- Compare application-level outputs, not circuit text alone.
- Run one bounded noisy simulation before a QPU.
- Record new package pins and update the experiment manifest.
Do not silence deprecation warnings globally. Treat them as scheduled migration work before Qiskit 3.0.
Raw lines 341 to 355