Q#
Microsoft's domain-specific language for quantum algorithms
Quick install
pip install qsharp Background and History
Q# (pronounced “Q sharp”) was announced by Microsoft in December 2017 as part of the Microsoft Quantum Development Kit. It is a domain-specific programming language designed exclusively for expressing quantum algorithms, developed by a team at Microsoft Research led by Krysta Svore. Microsoft’s approach was unusual in the quantum computing landscape: rather than building a Python library on top of existing tools, they created an entirely new language with a type system and compiler purpose-built for quantum concepts like qubit linearity (qubits cannot be copied or arbitrarily discarded) and automatic generation of adjoint and controlled operation variants.
The Q# language and QDK were part of Microsoft’s broader quantum computing strategy, which centered on topological qubits as the eventual hardware target. While Microsoft’s topological qubit research progressed more slowly than initially anticipated, Q# was designed to be hardware-independent and usable with any future quantum backend. The language shipped with a built-in full-state simulator, a Toffoli simulator, a sparse simulator, a resource estimator for projecting hardware requirements, and tight integration with Visual Studio and VS Code.
In early 2024, Microsoft released a modernized Q# compiler and runtime as part of the new Azure Quantum Development Kit. This overhaul, which accompanied the Q# 1.0 release, dropped the .NET dependency for the Python integration path, simplified the language in several areas, and added a browser-based compiler accessible through VS Code for the Web. The updated QDK includes a resource estimator that can project the physical qubit and runtime requirements of algorithms targeting fault-tolerant hardware — the most practically useful planning tool available for any quantum framework. In 2025, Microsoft announced Majorana 1, its first topological qubit chip, marking a milestone in the hardware strategy Q# was always designed to support.
Q# integrates with Azure Quantum, Microsoft’s cloud platform for quantum computing, which provides access to hardware from IonQ, Quantinuum, Rigetti, and others. As of 2025, Q# has a smaller user community than Qiskit or PennyLane, partly because its standalone language approach has a steeper learning curve than Python-based frameworks. However, it remains actively developed and is particularly valued for its resource estimation capabilities and its formal approach to quantum program correctness.
If you are coming from Python-first frameworks, the Q# vs Qiskit vs Cirq comparison on QuantumZeitgeist is a useful orientation. For hands-on learning, start with the Q# Hello World tutorial or work through the full Getting Started with Q# guide on this site.
Installation
Q# runs in three modes: VS Code extension (recommended for larger projects), Jupyter notebooks via Python (best for exploration), or the standalone qsharp CLI.
# Python integration (recommended for most users)
pip install qsharp
# VS Code: install "Azure Quantum Development Kit" extension
# Jupyter: qsharp kernel is included with the pip package
# Verify installation
python -c "import qsharp; print(qsharp.__version__)"
The Python package bundles the Q# compiler and simulator. No separate .NET installation is required as of Q# 1.x.
Q# Program Structure
Q# uses operations (with side effects, like quantum gates) and functions (pure classical computation). All quantum code lives inside operations. Namespaces group related operations and functions.
namespace MyProgram {
open Microsoft.Quantum.Intrinsic; // H, X, Y, Z, CNOT, M
open Microsoft.Quantum.Canon; // ApplyToEach, QFT, etc.
open Microsoft.Quantum.Measurement; // MResetZ, MeasureEachZ
operation BellState() : (Result, Result) {
use (q0, q1) = (Qubit(), Qubit());
H(q0);
CNOT(q0, q1);
return (MResetZ(q0), MResetZ(q1));
}
}
Key design rules:
- Qubits cannot be copied (no-cloning theorem enforced by the type system)
- Qubits must be returned to |0⟩ before the
useblock ends - Operations can have side effects; functions cannot
- The compiler auto-generates
AdjointandControlledvariants when declared
Types
| Type | Description |
|---|---|
Qubit | A quantum bit — not copyable, must be released in |
Result | Measurement outcome: Zero or One |
Bool | Classical boolean: true or false |
Int | 64-bit signed integer |
BigInt | Arbitrary-precision integer |
Double | 64-bit floating-point |
String | Immutable string (for Message() output) |
Pauli | PauliX, PauliY, PauliZ, PauliI |
Qubit[] | Qubit array |
Result[] | Measurement result array |
'T | Generic type parameter |
Unit | Void equivalent (return type when nothing is returned) |
(Int, Bool) | Tuple type |
Qubit Allocation
use q = Qubit(); // single qubit, starts in |0⟩
use qs = Qubit[4]; // array of 4 qubits
use (a, b) = (Qubit(), Qubit()); // tuple allocation
use (ctrl, targets) = (Qubit(), Qubit[3]); // mixed
// Qubits MUST be reset before release
Reset(q); // reset to |0⟩
ResetAll(qs); // reset entire array
MResetZ(q); // measure, then reset -- returns Result
Qubits start in state |0⟩ and must be returned to |0⟩ before the use block ends. The compiler will warn if qubits are potentially released in a non-|0⟩ state. This enforces clean resource management and is one of Q#‘s strongest safety guarantees.
The Bloch sphere simulator on this site is a useful visual aid for understanding qubit states before working with them in Q#.
Gates (Intrinsic Operations)
Single-qubit gates
H(q) // Hadamard: |0⟩ → (|0⟩+|1⟩)/√2
X(q) // Pauli-X (NOT gate)
Y(q) // Pauli-Y
Z(q) // Pauli-Z (phase flip)
S(q) // S gate (Z^½)
T(q) // T gate (Z^¼) -- building block for fault-tolerant circuits
I(q) // Identity
// Rotation gates (angles in radians)
Rx(theta, q) // rotation around X axis
Ry(theta, q) // rotation around Y axis
Rz(theta, q) // rotation around Z axis
R1(theta, q) // phase rotation: |1⟩ → e^(iθ)|1⟩
Two-qubit gates
CNOT(control, target) // Controlled-NOT
CZ(q1, q2) // Controlled-Z
SWAP(q1, q2) // SWAP
Multi-qubit gates
CCNOT(q1, q2, q3) // Toffoli (doubly-controlled NOT)
CSWAP(control, q1, q2) // Fredkin (controlled SWAP)
// General controlled versions
Controlled H([control], target)
Controlled X([c1, c2], target) // multi-control X
Controlled Rz(theta, [c], target)
See the quantum gates explained tutorial for a deeper walkthrough of what each gate does to qubit state.
Measurement
let result = M(q); // measure in Z basis → Result (Zero or One)
let result = MResetZ(q); // measure + reset to |0⟩ (preferred)
let result = MResetX(q); // measure in X basis + reset
let result = MResetY(q); // measure in Y basis + reset
// Multi-qubit
let results = MeasureEachZ(qs); // Result[], measures each qubit independently
let parity = Measure([PauliZ, PauliZ], [q0, q1]); // joint measurement
// Conditional on result
if result == One {
X(q); // classical feedforward
}
if result == Zero {
Message("Measured zero");
}
Measurement collapses the qubit to a definite state. In Q#, measurement always returns a classical Result value — there is no way to inspect the quantum state directly in a real execution (only in simulation).
Classical Control Flow
// Conditionals
if condition {
// ...
} elif other {
// ...
} else {
// ...
}
// For loops (bounded, required for adjoint generation)
for i in 0 .. n - 1 {
H(qs[i]);
}
for q in qs {
X(q);
}
// Repeat-until (for probabilistic algorithms)
repeat {
H(q);
let result = M(q);
} until result == Zero
fixup {
X(q); // runs if condition not met, then tries again
}
// While (for classical-only functions)
mutable i = 0;
while i < 10 {
set i += 1;
}
Variables
let x = 5; // immutable binding
mutable y = 0; // mutable variable
set y = 10; // update mutable
// Arrays
let arr = [1, 2, 3];
let first = arr[0];
let len = Length(arr);
let slice = arr[1 .. 2]; // [2, 3]
// Strings (for debugging output only)
Message($"Iteration {i}: result = {result}");
Adjoint and Controlled
Every operation can declare Adj, Ctl, or Adj + Ctl variants. The compiler generates them automatically when the body allows.
// Declaring an adjointable + controllable operation
operation MyOp(theta : Double, q : Qubit) : Unit is Adj + Ctl {
Rx(theta, q);
H(q);
T(q);
}
// Using the variants
Adjoint MyOp(theta, q); // inverse / uncomputation
Controlled MyOp([ctrl], theta, q); // controlled version
Adjoint Controlled MyOp([ctrl], theta, q);
This is one of Q#‘s most powerful features. Writing an operation once gives you the forward pass, the inverse (essential for uncomputation in quantum algorithms), and the controlled version automatically. The Grover’s Algorithm in Q# tutorial makes heavy use of this for oracle construction.
Canon Library
The Microsoft.Quantum.Canon namespace provides higher-level building blocks:
open Microsoft.Quantum.Canon;
open Microsoft.Quantum.Arithmetic;
// Apply to each qubit
ApplyToEach(H, qs); // H to every qubit
ApplyToEachA(H, qs); // Adj variant
ApplyToEachCA(H, qs); // Adj + Ctl variant
// Quantum Fourier Transform
QFT(qs);
Adjoint QFT(qs); // inverse QFT (used in QPE)
// Arithmetic
let (sum, carry) = RippleCarryAdderD(a, b);
The Quantum Phase Estimation in Q# tutorial demonstrates QFT and Adjoint QFT in a full working implementation.
Running from Python
The recommended workflow for exploration and testing:
import qsharp
# Evaluate a Q# expression directly
result = qsharp.eval("""
use q = Qubit();
H(q);
let r = MResetZ(q);
r
""")
print(result) # qsharp.Result.Zero or qsharp.Result.One
# Run with multiple shots
results = qsharp.run("""
use (q0, q1) = (Qubit(), Qubit());
H(q0);
CNOT(q0, q1);
let r = (MResetZ(q0), MResetZ(q1));
r
""", shots=1000)
zeros = sum(1 for r in results if r == (qsharp.Result.Zero, qsharp.Result.Zero))
ones = sum(1 for r in results if r == (qsharp.Result.One, qsharp.Result.One))
print(f"|00⟩: {zeros/10:.1f}% |11⟩: {ones/10:.1f}%")
# expect: |00⟩: ~50% |11⟩: ~50%
Loading a .qs file
import qsharp
# Load and compile a Q# source file
qsharp.eval(open("MyAlgorithm.qs").read())
# Run an operation from it
results = qsharp.run("MyNamespace.MyOperation()", shots=500)
See the Hello World in Q# tutorial for a complete working example from installation to first run.
Resource Estimation
One of Q#‘s flagship features — estimate how much fault-tolerant hardware an algorithm would require without running it on a real device:
import qsharp
# Estimate resources for a Q# operation
result = qsharp.estimate("""
use qs = Qubit[10];
// ... your algorithm ...
ResetAll(qs);
""")
print(result["physicalCounts"]["physicalQubits"])
print(result["physicalCounts"]["runtime"])
The resource estimator accounts for error correction overhead, magic state distillation, T gate cost, and target hardware parameters. It is the most rigorous planning tool available for projecting real-world fault-tolerant requirements.
Azure Quantum
To run on real hardware through Azure:
import azure.quantum
from azure.quantum.target.microsoft import MicrosoftEstimator
workspace = azure.quantum.Workspace(
subscription_id="your-subscription-id",
resource_group="your-resource-group",
name="your-workspace",
location="eastus"
)
# List available targets (hardware providers)
for target in workspace.get_targets():
print(target.name)
# ionq.simulator, ionq.qpu, quantinuum.hqs-lt-s1, rigetti.sim.qvm, ...
# Submit a Q# job to IonQ
job = workspace.submit_job(
target_name="ionq.simulator",
input_data=qsharp_source,
input_data_format="qsharp.v2",
shots=100
)
result = job.get_results()
Azure Quantum currently provides access to IonQ (trapped-ion), Quantinuum (trapped-ion), and Rigetti (superconducting) hardware. See Getting Started with Microsoft Azure Quantum on QuantumZeitgeist for a practical walkthrough of the platform.
Common Patterns
Bell state
operation BellPair(q0 : Qubit, q1 : Qubit) : Unit is Adj + Ctl {
H(q0);
CNOT(q0, q1);
}
operation RunBell() : (Result, Result) {
use (q0, q1) = (Qubit(), Qubit());
BellPair(q0, q1);
return (MResetZ(q0), MResetZ(q1));
}
Phase kickback
Used in algorithms like Grover’s algorithm and Bernstein-Vazirani to transfer phase information from a target qubit to a control:
operation PhaseKickback(oracle : (Qubit => Unit is Adj + Ctl), control : Qubit) : Unit is Adj {
use target = Qubit();
X(target); // put target in |1⟩
H(control); // control into superposition
Controlled oracle([control], target); // phase kickback
H(control);
Reset(target);
}
Repeat-until-success (RUS)
For probabilistic state preparation or non-deterministic algorithms:
operation PrepareArbitraryState(q : Qubit) : Unit {
mutable done = false;
repeat {
H(q);
let r = M(q);
set done = (r == Zero);
} until done
fixup {
Reset(q); // reset and try again
}
}
Quantum phase estimation (QPE) skeleton
See the full Quantum Phase Estimation in Q# tutorial for a complete implementation. The skeleton:
operation QuantumPhaseEstimation(
oracle : ((Int, Qubit) => Unit is Adj + Ctl),
eigenstate : Qubit,
precision : Int
) : Double {
use countingRegister = Qubit[precision];
ApplyToEach(H, countingRegister);
for (idx, ctrl) in Enumerated(countingRegister) {
Controlled oracle([ctrl], (1 <<< idx, eigenstate));
}
Adjoint QFT(countingRegister);
let results = MeasureEachZ(countingRegister);
ResetAll(countingRegister);
// convert results to phase estimate...
return 0.0;
}
Debugging and Output
// Print to console (simulator only)
Message("Hello from Q#");
Message($"Qubit count: {Length(qs)}");
Message($"Result: {result}");
// Dump state (simulator only -- not available on hardware)
DumpMachine(); // prints full state vector
DumpRegister(qs); // prints state of a specific register
// Assertions (fail loudly in simulation, stripped on hardware)
Fact(Length(qs) == 4, "Expected 4 qubits");
EqualityFactI(count, 3, "Count should be 3");
Error Correction in Q#
Q# has built-in support for quantum error correction primitives. See the Quantum Error Correction in Q# tutorial for a hands-on introduction to stabilizer codes and syndrome measurement in Q#.
open Microsoft.Quantum.ErrorCorrection;
// Encode a logical qubit using the 3-qubit bit-flip code
operation EncodeInBitFlipCode(physical : Qubit[]) : LogicalRegister {
CNOT(physical[0], physical[1]);
CNOT(physical[0], physical[2]);
return LogicalRegister(physical);
}
Q# vs Other Frameworks
| Feature | Q# | Qiskit | PennyLane |
|---|---|---|---|
| Language | Standalone DSL | Python library | Python library |
| Autodiff / gradients | No | Partial | Yes (core feature) |
| Resource estimation | Excellent | Limited | No |
| Adjoint auto-generation | Yes | Manual | Manual |
| Hardware access | Azure Quantum | IBM Quantum | Multiple backends |
| Learning curve | Steep | Moderate | Moderate |
| Best for | Fault-tolerant algorithms, resource planning | Gate-level control, IBM hardware | Variational algorithms, QML |
If you are primarily interested in variational algorithms and machine learning, PennyLane is a better fit. If you want the deepest integration with IBM’s hardware ecosystem, Qiskit is the standard. Q# is the right choice if you care about long-term algorithm correctness, formal resource estimation, and eventual fault-tolerant hardware.
Learning Resources
On this site:
- Hello World in Q# — installation to first circuit
- Getting Started with Q# — operations, types, measurement, and running on hardware
- Grover’s Algorithm in Q# — the canonical quantum search speedup
- Quantum Phase Estimation in Q# — QPE with QFT
- Quantum Chemistry Simulation with Q# — molecular energy estimation
- Quantum Error Correction in Q# — stabilizer codes
Courses:
- Quantum Katas — Microsoft’s self-paced interactive exercises, free
- Quantum Programming with Q# (edX) — structured course from Microsoft
- Azure Quantum Learning Path — Microsoft’s official learning path
- Azure Quantum Developer Certification — Microsoft credential
External:
- Top 20 Q# Terms to Know — QuantumZeitgeist glossary companion
- Introduction to Q# — 5-minute primer on QuantumZeitgeist
- Q# and Machine Learning — applying Q# to ML problems
- Official Q# documentation — Microsoft Learn
- Q# GitHub repository — source, issues, and samples