PennyLane
Install
Install

Related materials

  • Related contentA Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery
  • Related contentIntroducing lattice surgery
  • Related contentQuantum low-density parity-check (qLDPC) codes for quantum error correction

Contents

  1. Introduction
  2. Stabilizers
  3. Logical operators: Z and X edges
  4. Error detection and correction
  5. Quantum computation via lattice surgery
  6. Conclusion
  7. References
  8. About the author

Downloads

  • Download Python script
  • Download Notebook
  • View on GitHub
  1. Demos/
  2. Quantum Computing/
  3. Introducing the Surface Code

Introducing the Surface Code

Korbinian Kottmann

Korbinian Kottmann

Published: July 13, 2026. Last updated: July 13, 2026.

The surface code is the gold standard for deploying quantum error correction (QEC) on hardware today. Not only does it provide a high circuit-level error threshold (around 1%), but it only requires local connectivity, making it amenable to hardware with 2D nearest-neighbor connectivity, such as superconducting qubits.

Beyond it being a fully-functioning QEC code, it serves as a great introduction to the world of fault-tolerant quantum computing (FTQC), because its working principles are ubiquitous in most modern QEC codes such as qLDPC codes that break the locality requirement and are more qubit efficient.

A lot has happened since its early inception in the 90s, so we are going to give a modern 2026 overview of its components in this demo. In particular, we are going to learn about stabilizers, logical operators, Pauli based computation via lattice surgery, and error detection & correction — all of which are also relevant in more general qLDPC codes.

demos/_static/demo_thumbnails/large_demo_thumbnails/pennylane-demo-surface-code-large-thumbnail.png

Introduction

We are going to take a look at the planar, two-dimensional, rotated surface code. This is a modern variant of the Kitaev surface code [1] [2] and not to be confused with the toric code or one of the many other variants that generalize it.

The rotated surface code consists of alternating X (blue) and Z (yellow) squares that make up a lattice. The so-called data qubits sit on the vertices (highlighted in pink). These will be the qubits that encode the quantum information of a \(d \times d\) surface code patch that makes up a single logical qubit (we will use \(d=5\) throughout for simplicity):

../../_images/surface_code_syndrome.png

We additionally have so-called syndrome qubits (in light gray) that sit in the middle of the squares or keystones of the arches. These syndrome qubits are used to continuously perform measurements on the surrounding data qubits in a non-destructive way. These operators being measured are called stabilizers and make up the backbone of almost all modern QEC codes. In the rotated surface code, they are alternating squares with a product of four \(X\) or \(Z\) operators. Additionally, there are weight-2 \(X\) and \(Z\) arches on the edges (more on that later). These suffice to detect any arbitrary \(X\), \(Y\), or \(Z\) error of weight up to \(d-1\).

../../_images/surface_code_with_stabilizers.png

These stabilizers on the data qubits are measured indirectly via the syndrome qubits. This is done by entangling the data qubits with the corresponding syndrome qubit and then measuring that (see also Fig. 2 in [4]).

../../_images/syndrome_measurements.png

The measurement result or $-1$ or $+1$ of a stabilizer measurement indicates whether or not an error has occurred, respectively. A \(d \times d\) surface code qubit is said to have code-distance \(d\) and can detect up to \(d-1\) errors, and correct up to \(\left\lfloor \tfrac{d-1}{2} \right\rfloor\). When more errors occur, they may go unnoticed or get corrected in the wrong way, as we will see later.

Before we get into more detail and expand on each of these components, we want to stress the difference between the rotated surface code (left) to the original planar surface code (right):

../../_images/rotated.png

In the central image we see their correspondences. Note that the solid pink lines are merely a guide to the eye and do not represent physical connectivity. They are typically used in this way to discern face plaquette operators of \(Z\) stabilizers, and vertex or star operators of \(X\) stabilizers. They are very similar, but the rotated surface code effectively halves the required qubits from \(4d^2 - 4d + 1\) to \(2d^2-1\) for a given code-distance \(d\).

For the purpose of this demo, we shall refer to it just as the surface code.

Stabilizers

The surface code is a stabilizer code, which means that quantum information is encoded in the joint \(+1\) eigenspace of a set of commuting observables \(\mathcal{S}\) called stabilizers. These stabilizers \(S_i \in \mathcal{S}\) are products of four (or two) \(Z\) or \(X\) operators arranged in a checkerboard.

../../_images/surface_code_with_stabilizers.png

All these stabilizers commute with each other - that is one of their defining properties. For the surface code layout shown here, you can easily verify this using the rule that two Pauli words commute if and only if they anticommute on an even number of sites. Take for example the simplest case, two sites [0, 1], such that we have \([X_0 X_1, Z_0 Z_1] = 0\).

The measurement outcome of such a stabilizer is binary \(\pm 1\) and we assume that the underlying quantum state \(|\psi\rangle\) that is encoded by the qubit of the surface code is in the so-called code (sub)space - the joint \(+1\) eigenspace of all stabilizer measurements. That means that the action of any stabilizer \(S_i \in \mathcal{S}\) on a state \(|\psi\rangle\) in the code space is equal to the identity, \(S_i |\psi\rangle = + 1 |\psi\rangle\).

By continuously measuring all stabilizers we can ensure that the state is not leaving the code space. Because the stabilizer measurement itself is prone to error (the CNOT and Hadamard gates in the syndrome extraction circuit above are noisy), we typically repeat this process, performing \(d\) rounds of syndrome extraction. A single parallel measurement of all stabilizers is called a round. Repeating this measurement \(d\) times builds a historical timeline that helps us isolate the root cause of an error. A true data qubit error alters the system permanently, leading to a persistent, repeated change in the error syndrome over time. In contrast, a measurement error behaves like a temporary glitch, manifesting as an isolated, singular event in the syndrome history. Once the former is identified across these \(d\) rounds, the system must account for it and correct it. As we will see later, this correction is handled entirely in software, bypassing the need to apply error correction operations physically.

Overall, these stabilizer measurements allow us to deterministically detect up to \(d-1\) single-qubit \(X\), \(Y\), or \(Z\) errors. Larger error strings that are equivalent to logical operators cannot be detected, as we will see in the next section.

Logical operators: Z and X edges

You may have noticed that we have weight-2 stabilizers (arches) at the edges of our surface code patch. These are crucial for defining logical operators on the surface code patch.

Logical operators \(Z_L\) or \(X_L\) need to commute with all stabilizers so they don’t move our state outside the code space. At the same time, they must not be stabilizers (or products thereof) themselves. On top of that, they of course need to satisfy the fundamental anti-commutation relation \(X_L Z_L = -Z_L X_L\).

On a rotated surface code, these operators form physical chains across the lattice. A logical \(X_L\) operator is a string of Pauli \(X\) operators on data qubits that connects the two edges with \(X\) arches (left and right here). And vice versa for a logical \(Z_L\) operator, as indicated below.

Multiplying a logical operator by a stabilizer does not change the underlying logical state, so the string on the right hand side is an equivalent logical operator (recall that \(Z^2=\mathbb{1}\)).

../../_images/Z_string.png

We can continue to deform the string to arrive at a logical \(Z_L\) operator that goes along the right edge.

../../_images/Z_edge.png

This is why the left and right edges are called \(Z\) edges, which may be confusing because they contain \(X\) arches. The opposite is true for the top and bottom \(X\) edges with \(Z\) arches.

These arches define the logical operators, but they are also crucial from a mathematical point of view and restrict our \(d \times d\) patch to exactly one logical qubit. That is because the number of encoded qubits \(k\) is given by the difference of data qubits \(n\) and independent stabilizers \(s\), so \(k = n - s\). For the \(5 \times 5\) patch we are considering, we have \(n=25\) data qubits and \(16\) weight-4 stabilizers. Together with the \(8\) arches we get \(k = 25 - 16 - 8 = 1\).

The arches are also important for coverage of all possible errors. E.g., if a \(X\) error occurred on the top left data qubit, only the top left \(Z\) arch would catch it.

Error detection and correction

Let us first consider what actually happens if a single \(Z\) error occurs on one of the data qubits. The story works equivalently for \(X\) and \(Y\) errors. Before the \(Z\) error, each stabilizer measurement returns \(+1\), confirming the underlying state is in the correct code space. Now let us assume the central data qubit experiences a \(Z\) error. The surrounding \(Z\) stabilizers are unaffected by it, but the two \(X\) stabilizers yield a \(-1\) measurement - a defect, indicated by \(-1\) on the stabilizer square.

../../_images/Z_error.png

The tricky part about error correction is that we are only ever given the information of the syndrome measurements and do not know what actually has physically happened. The same error syndromes could have also occurred due to, e.g., the following error pattern.

../../_images/unlikely_error.png

This scenario is, however, exponentially more unlikely. A common decoding algorithm is Minimum-Weight Perfect Matching (MWPM). It pairs up the observed flipped stabilizers by finding the shortest, and therefore most likely, chain of physical errors that could have caused them. In the scenario in the image above, the (by far) most likely error string is simply the central \(Z\) error.

Consider the following situation, where two different weight-2 error strings lead to the same error syndrome.

../../_images/same_weight_two.png

Here, both errors have the same weight, so the choice for an MWPM decoder is ambiguous. Luckily, it does not matter which error we correct, as they are logically equivalent: they are the same error up to a \(Z\) stabilizer, in particular the one on the surface between the two defects.

In the following scenario, however, we will run into a real problem. Both error strings again lead to the same defect syndrome.

../../_images/fatal_error.png

Now, if the (less likely) error with three errors occurs, but we correct for the (more likely) second scenario, we overall perform a logical \(Z_L\) operation, and introduce an undetected error in our computation. This is a manifestation of the fact that a distance \(d=5\) rotated surface code qubit can only correct

\[t = \left\lfloor \frac{d-1}{2} \right\rfloor = 2\]

errors deterministically.

Intuitively, this makes sense. In a code with distance \(d\), logical operators are (at least) of weight \(d\). Logical operators change the logical state of the qubit without being noticed by any stabilizer. So the best we can do is detect errors up to \(d-1\). And we can only deterministically correct errors up to half the distance, because a wrong correction will make the total operation (error + correction) a logical operator that goes unnoticed.

Error correction is continuously performed during computation. Measuring all \(\mathcal{O}(d^2)\) stabilizers once (and typically in parallel) constitutes one round, which is often called a QEC clock cycle in hardware. A logical clock cycle corresponds to repeating these stabilizer measurements \(d\) times to ensure fault tolerance. We typically measure the runtime of a computation in logical clock cycles. Most notably, a Pauli product measurement can be performed in one logical clock cycle.

Finally, the actual error correction typically happens in software, and no physical correction terms are actively applied. Instead, one can track all detected errors based on their syndromes and then multiply them retrospectively with the final measurement results at the end of the computation. This reduces the runtime of the quantum computation as it avoids additional physical computations.

Quantum computation via lattice surgery

There are different variants of how to perform quantum computation with the surface code. Braiding is an older approach [5], but most modern approaches use lattice surgery [7] [6]. The concept is relatively simple: To measure \(Z_L \otimes Z_L\) between two surface code qubits, simply connect them via their \(Z\) edge (lattice merging), perform \(d\) rounds of measuring all stabilizers, including the intermediary ones, and finally destructively measure in between the two patches to split them again (lattice splitting). The logical \(Z_L \otimes Z_L\) measurement is indirectly determined via the product of the intermediate boundary stabilizers measured during those rounds of error correction. Note that this is different from terminal measurements where data qubits are measured directly. A \(X_L \otimes X_L\) measurement works analogously, but we stitch the two surface code patches along their \(X\) edges (see our lattice surgery demo for more details).

../../_images/lattice_surgery.png

This is important because most modern surface code constructions are targeting Pauli based computation, where all logical operations can be reduced to such Pauli product measurements.

In fact, in the Game of Surface Codes [8], a popular framework for thinking about fault tolerant quantum computers, we forget about everything but the \(X\) and \(Z\) edges of our qubit patches. This results in rectangular boxes with solid (\(Z\)) and dotted (\(X\)) edges. The same \(Z_L \otimes Z_L\) measurement from above can be portrayed as

../../_images/gosc.png

This diagram simply says, we measure qubits \(|q_1\rangle\) and \(|q_2\rangle\) along their \(Z\) edges via an intermediate auxiliary qubit region, indicated by the blue connection. So overall, this is just the joint measurement of \(Z_{q_1} \otimes Z_{q_2}\) via their \(Z\) edges.

Conclusion

In this demo, we have learned about the basics of modern rotated surface codes from qubit definitions and stabilizers to logical operators, error decoding, and computation. Most modern quantum error correction codes such as qLDPC codes work under the same principles, so you should be well-prepared for continuing your QEC journey down this path.

References

[1]

A. Yu. Kitaev, “Fault-tolerant quantum computation by anyons”, arXiv:quant-ph/9707021, 1997

[2]

Sergey B. Bravyi, A. Yu. Kitaev, “Quantum codes on a lattice with boundary”, arXiv:quant-ph/9811052, 1998

[3]

Austin G. Fowler, Matteo Mariantoni, John M. Martinis, Andrew N. Cleland, “Surface codes: Towards practical large-scale quantum computation”, arXiv:1208.0928, 2012

[4]

Yu Tomita, Krysta M. Svore “Low-distance Surface Codes under Realistic Quantum Noise”, arXiv:1404.3747, 2014

[5]

Robert Raussendorf, Jim Harrington, Kovid Goyal, “Topological fault-tolerance in cluster state quantum computation”, arXiv:quant-ph/0703143, 2007

[6]

Dominic Horsman, Austin G. Fowler, Simon Devitt, Rodney Van Meter, “Surface code quantum computing by lattice surgery”, arXiv:1111.4022, 2011

[7]

Austin G. Fowler, Craig Gidney “Low overhead quantum computation using lattice surgery” arXiv:1808.06709, 2018.

[8]

Daniel Litinski “A Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery” arXiv:1808.02892, 2018.

About the author

Korbinian Kottmann
Korbinian Kottmann

Korbinian Kottmann

Korbinian likes simulating quantum systems, whether it be via tensor network methods during his PhD, or with quantum computers at Xanadu. Currently, he works on quantum compilation to make simulation algorithms go brrr.

Share demo

Ask a question on the forum

Related Demos

A Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery

Introducing lattice surgery

Quantum low-density parity-check (qLDPC) codes for quantum error correction

Modeling the toric code on a quantum computer

Stabilizer codes for quantum error correction

Understanding the Fault-tolerant Threshold Theorem in Practice

Measurement-based quantum computation

Active volume

Loom x Catalyst: designing, orchestrating, and automating quantum error correction experiments

What are magic states?

Never miss a milestone

Get the latest quantum updates delivered to your inbox.

Join the list
PennyLane

PennyLane is an open-source quantum software platform for quantum computing, quantum machine learning, and quantum chemistry. Create meaningful quantum algorithms, from inspiration to implementation.

Created with ❤️ by Xanadu.

Research

  • Research

  • Performance

  • Hardware and simulators

  • Demos library

  • Compilation hub

  • Quantum datasets

Education

  • Teach

  • Learn

  • Codebook

  • Coding challenges

  • Videos

  • Glossary

Software

  • Install

  • Features

  • PennyLane documentation

  • Catalyst documentation

  • Development guide

  • How-to guides

  • API

  • GitHub


Xanadu

© Copyright 2026 | Xanadu | All rights reserved

TensorFlow, the TensorFlow logo and any related marks are trademarks of Google Inc.

Privacy policyTerms of serviceCookies policyCode of conduct