Seurat or scanpy: which should your lab standardise on?

A practical comparison of the two dominant single-cell toolkits — where each is genuinely better, where results differ, and what that means if you switch mid-project.

Updated 2026-07-31

Do this on your own data: the choice matters far less than whether the script that produced the figures still runs a year from now. This is the reproducible form we hand over: omics.hstgenomics.com/code. The analysis it produces: omics.hstgenomics.com/sample.

Want it done rather than explained? We do analysis only — send a count matrix, an h5ad or Seurat object, Cell Ranger output or a public accession and get publication-ready results with the code that produced them, at a fixed price agreed before any work starts: omics.hstgenomics.com/quote.

Both do the same core analysis competently. The choice matters less than people argue and more than "either is fine" suggests, because the differences show up exactly where projects get stuck.

Where each genuinely wins

Seurat (R) — closer to the statistical ecosystem most wet-lab groups already live in. If your differential expression will end up in DESeq2 or edgeR, if your collaborators send you R scripts, or if your figures are made in ggplot2, staying in R removes a translation layer. The vignettes are also the most beginner-friendly documentation in the field.

scanpy (Python) — better at scale and better connected to machine-learning tooling. Above roughly 200,000 cells the memory behaviour and the sparse handling matter, and anything involving scVI, CellTypist, squidpy for spatial, or a deep-learning component is a shorter path in Python. The h5ad format is also the de facto currency for public single-cell data.

Where results actually differ

Run the same dataset through both and you will not get identical clusters. The usual causes:

  • Normalisation defaults. Seurat's SCTransform and scanpy's normalize_total plus log1p are different models, not different spellings of the same thing.
  • HVG selection. Different methods and defaults select overlapping but distinct gene sets, which changes the PCA and everything downstream.
  • Neighbour graph parameters. Different defaults for k and for the distance metric.
  • Clustering. Louvain versus Leiden, and different default resolutions.

None of these makes one wrong. It means cluster counts are not a fact about your data alone — they are a fact about your data and your parameters, which is why reporting the parameters matters more than reporting the number.

If you have to move between them

Conversion works but loses things. h5ad to Seurat and back handles counts, embeddings and basic metadata; it commonly drops layers, graph objects and some unstructured annotations. Convert once, early, rather than repeatedly — a project that bounces between formats accumulates silent losses that nobody notices until a figure cannot be regenerated.

Practical route: keep the raw counts as the source of truth in a plain format, and treat any processed object as disposable output that can be rebuilt from the script.

What to standardise on

If your group is R-native and your datasets are under 100,000 cells: Seurat. If you are Python-native, at scale, or heading towards spatial and model-based methods: scanpy. If you are starting from zero in 2026 and have no constraint: scanpy, because the public data, the spatial ecosystem and most new methods land there first.

Whichever you pick, the thing that actually determines whether your analysis survives review is not the toolkit — it is whether the statistical unit is the subject rather than the cell (why), and whether anyone can re-run it (what that looks like).

Need this done rather than explained?

We do analysis only — send a count matrix, an h5ad/Seurat object or a public accession and get publication-ready results with the code that produced them. Fixed price agreed before work starts.

→ Get a fixed quote  ·  See a full sample deliverable

More guides