OMICSDESKbioinformatics, delivered

Getting a Seurat object to an analyst (and getting it back)

Converting between Seurat and h5ad, what silently goes missing on the way, and the two-line fallback that works when nothing installs.

Updated 2026-08-02

Most single-cell work in the field lives in a Seurat object; most analysis tooling published in the last few years reads h5ad. Moving between them is routine, and it goes wrong in a small number of predictable ways — almost all of which are silent.

The short version: convert with SeuratDisk if it installs, fall back to writing the count matrix plus two text files if it does not, and in either case send raw counts rather than normalised values. The single most common problem we see is not a failed conversion — it is a successful conversion of the wrong layer.

The straightforward route

library(Seurat)
library(SeuratDisk)

SaveH5Seurat(obj, filename = "data.h5Seurat")
Convert("data.h5Seurat", dest = "h5ad")   # produces data.h5ad

Check the result before sending it: the file should be roughly the size of your matrix, and Convert() writes whichever assay is currently active. If your object has SCT, integrated and RNA assays, set DefaultAssay(obj) <- "RNA" first unless you specifically want the others.

The fallback when nothing installs

SeuratDisk depends on a chain of packages that regularly conflicts with whatever R version a cluster has. This always works:

counts <- Seurat::GetAssayData(obj, assay = "RNA", layer = "counts")
Matrix::writeMM(counts, "matrix.mtx")
write.table(rownames(counts), "features.tsv", quote = FALSE, row.names = FALSE, col.names = FALSE)
write.table(colnames(counts), "barcodes.tsv", quote = FALSE, row.names = FALSE, col.names = FALSE)
write.csv(obj@meta.data, "metadata.csv")           # sample, condition, cluster labels…

Zip those four files together. Any analyst can read them, and the metadata file is what makes a group comparison possible at all — without a sample or donor column, no one can test between conditions no matter how many cells there are.

What goes missing, in order of how often it matters

  1. The wrong layer. data holds log-normalised values, counts holds integers. Differential expression tools expect counts and will produce confident nonsense from normalised input. If your matrix has decimals in it, it is not counts.
  2. Only one assay survives. Conversions carry the active assay. Antibody capture, integrated data and SCT residuals are separate assays and are usually dropped silently.
  3. Dimensional reductions and graphs. UMAP coordinates often survive; the neighbour graph usually does not. This is rarely a problem — they can be recomputed — but it means the receiving analyst may not reproduce your exact figure, and that is worth saying up front rather than treating as an error.
  4. Factor levels and colours. Cluster identities come across as strings, so ordering is lost. If the order matters for a figure, send it written down.
  5. Anything in @misc or custom slots. Not carried. If a result you care about lives there, export it separately as a table.

Coming back the other way

Convert("results.h5ad", dest = "h5seurat", overwrite = TRUE)
obj <- LoadH5Seurat("results.h5seurat")

Expect the same losses in reverse. In practice the more robust handover is a plain table of per-cell annotations (barcode, cluster, cell type, any scores) that you merge into your own object with AddMetaData() — it cannot break, and you keep the object you already trust.

A note on what to send for a quote

You do not need to convert anything to get a price. Cell count, median genes per cell, tissue and the comparison you want are enough — our no-upload self-check works from five numbers and never sees your data. If you do want the free QC report, it reads .h5ad, 10x .h5, .loom, .mtx, .csv/.tsv, and a zipped Cell Ranger output directory; R objects are the one thing it cannot read, which is why this page exists.

More on what to include with a dataset: how to hand data to an analyst and sharing data safely.

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