# Single-cell RNA-seq analysis: a best-practice workflow from FASTQ to figures
URL: https://omicsquest.com/insights/single-cell-rna-seq-analysis-best-practices/

A step-by-step scRNA-seq workflow: alignment, empty droplets, ambient RNA, doublets, QC, integration, annotation, pseudobulk DE and trajectories.

Key takeaways:
- Remove technical artifacts (empty droplets, ambient RNA, doublets) **before** clustering, or they become clusters.
- Set QC thresholds per sample with data-driven cutoffs, not one global mitochondrial percentage.
- Benchmark integration: the goal is to remove batch while keeping biological differences between conditions.
- Annotate with markers *and* biology; cluster numbers are not cell types.
- Compare conditions with **pseudobulk** or mixed models. The biological replicate, not the cell, is the unit of inference.

Single-cell RNA sequencing (scRNA-seq) measures gene expression in thousands to millions of individual cells. The data is sparse and noisy, and full of technical artifacts that look like biology. A sound analysis removes those artifacts first, then asks biological questions with statistics that respect the experimental design.

This guide describes the workflow our bioinformaticians and cell biologists use for 10x Genomics Chromium and similar droplet or combinatorial-indexing data. It follows the community best practices summarized by Luecken and Theis and, more recently, Heumos and colleagues, plus what we have learned from rescuing analyses that did not survive peer review.

## Step 1: Alignment and counting

Start from FASTQ (or BCL) files when you can. Re-running alignment lets you confirm the chemistry, the reference genome and annotation version, and whether intronic reads were counted.

- **Cell Ranger** is the 10x reference implementation and the safest default for 10x data.
- **STARsolo**, **alevin-fry** and **kallisto|bustools** are faster, open alternatives with near-identical results when configured to match.
- For **single-nucleus RNA-seq**, include intronic reads. Most nuclear transcripts are unspliced, and excluding introns throws away much of the signal.

Record the reference build (for example GRCh38 with a specific GENCODE release). Mixing references across samples is a quiet source of batch effects.

## Step 2: Separate cells from empty droplets

Most barcodes in a droplet experiment are empty droplets that contain only ambient RNA. Simple knee-point thresholds discard real cells with low RNA content, such as neutrophils, quiescent cells and many nuclei. Statistical methods such as **EmptyDrops** test each barcode against the ambient profile and recover these cells.

## Step 3: Correct ambient RNA

Free-floating transcripts from lysed cells end up in every droplet. In practice this means hemoglobin genes in every blood-adjacent sample, immunoglobulin transcripts in every cell near plasma cells, and tissue-specific secreted genes everywhere. Uncorrected, ambient RNA:

- creates false marker expression (for example "T cells" expressing *LYZ*),
- produces spurious differential expression when ambient levels differ between samples, and
- blurs cluster boundaries.

**CellBender** and **SoupX** both estimate and remove the ambient profile. We run correction per sample and check that known lineage-exclusive markers become mutually exclusive afterwards.

## Step 4: Detect and remove doublets

Doublets are droplets that captured two cells. Heterotypic doublets, made of two different cell types, co-express markers from both and often form small "intermediate" clusters that look like transitional states. **scDblFinder** and **DoubletFinder** simulate artificial doublets and score each barcode's similarity to them. Run detection per sample, because doublets only form within a capture lane.

<div class="callout" markdown="1">
**What our experts avoid:** naming a cluster that co-expresses markers of two lineages before ruling out doublets. It is the single most common error we find in rescued single-cell projects. See our [case study on a "novel" population that was doublets](/case-studies/novel-cluster-was-doublets/).
</div>

## Step 5: Quality control with adaptive thresholds

Classic QC metrics are counts per cell, genes per cell and the fraction of mitochondrial reads. The mistake is applying one fixed cutoff, such as "under 10% mitochondrial", to every sample and cell type. Metabolically active cells (cardiomyocytes, hepatocytes, some tumor cells) have high mitochondrial fractions for real biological reasons. Damaged cells in a poor sample can sit under any fixed cutoff.

We use per-sample thresholds based on the median absolute deviation (MAD), typically 3 to 5 MADs. We then check the removed cells: are they concentrated in one cell type? If so, the threshold is removing biology.

## Step 6: Normalization and feature selection

- **Shifted log normalization** (counts per cell scaled to a common size, then log1p) works well for most analyses.
- **scran pooling** size factors handle heterogeneous populations better.
- **SCTransform** (regularized negative binomial regression) is a strong choice in Seurat workflows.

Select 2,000 to 5,000 highly variable genes for dimensionality reduction. Compute them per batch and combine, so one sample's variation does not dominate.

## Step 7: Integration across samples

With multiple samples, technical differences (capture date, chemistry lot, sequencing depth) separate cells by sample rather than by biology. Integration methods align samples in a shared space:

| Method | Approach | When we use it |
|---|---|---|
| Harmony | Iterative correction of PCA embeddings | Fast default for moderate batch effects |
| scVI / scANVI | Deep generative model of counts | Complex designs, many batches, atlas mapping |
| Seurat v5 integration | Anchors, CCA/RPCA | Seurat-native workflows |
| BBKNN | Batch-balanced neighbor graph | Very large datasets |

Benchmarks by Luecken and colleagues show that no method wins everywhere. We score integration with **batch removal** and **biological conservation** metrics (scIB), and we check that condition-specific populations still separate. Over-correction can erase the very biology you are testing. Our [integration guide](/insights/single-cell-batch-correction-integration/) covers this in depth.

## Step 8: Clustering

Build a k-nearest-neighbor graph on the integrated embedding and cluster with the Leiden algorithm. The resolution parameter decides how many clusters you get, so treat it as a decision. We cluster at several resolutions, follow how clusters split with a clustering tree, and check stability by subsampling. Clusters that appear only at one resolution, or that are defined by stress or cell-cycle genes, need a closer look before they are named.

UMAP and t-SNE are visualization tools. Distances between clusters on a UMAP are not meaningful, so never draw biological conclusions from cluster positions on the plot.

## Step 9: Cell-type annotation

Good annotation combines three sources of evidence:

1. **Canonical markers** checked by a biologist, with literature support for each label.
2. **Reference mapping** onto published atlases with tools such as Azimuth, CellTypist or scArches.
3. **Biological plausibility**: does this cell type belong in this tissue, in these proportions?

Annotate hierarchically: major lineages first, then subcluster each compartment. Attach a confidence level to each label. "Activated fibroblast, high confidence" and "possible transitional state, low confidence" are both honest and useful.

## Step 10: Compare conditions correctly

This is where most published single-cell errors happen. Cells from the same donor are not independent. Testing 5,000 cells from three mice against 5,000 cells from three other mice with a cell-level Wilcoxon test inflates significance enormously. Squair and colleagues showed that pseudobulk methods, which aggregate counts per sample and cell type before testing, consistently outperform cell-level tests in false discovery control.

- **Differential expression:** pseudobulk with DESeq2, edgeR or limma-voom, or mixed models with a donor random effect. See our [pseudobulk guide](/insights/pseudobulk-differential-expression-single-cell/).
- **Differential abundance:** test composition changes with Milo (neighborhood-level), scCODA (compositional) or propeller, not with raw proportions.

## Step 11: Downstream biology

With clean, annotated data and correct comparisons, add the analyses that answer your question:

- **Trajectories and pseudotime** (Slingshot, PAGA, Monocle 3, Palantir) for differentiation and activation processes.
- **RNA velocity** (scVelo) and **fate mapping** (CellRank). Treat velocity as a hypothesis, since its kinetic assumptions often fail.
- **Gene regulatory networks** (pySCENIC) and **TF activity** (decoupleR).
- **Cell-cell communication** (LIANA, CellChat, NicheNet). Different resources and methods disagree, so we use consensus approaches and compare conditions rather than reporting raw interaction lists.
- **Gene programs** (cNMF, Hotspot) for continuous states that clusters split arbitrarily.

## Step 12: Deliver reproducible results

A finished analysis is more than figures. It should include annotated objects (h5ad and Seurat), versioned code, software versions, parameters for every step, and a methods section that a reviewer can follow. Our deliverables include all of these by default, plus unlimited figure customization for journal formatting.

## How OmicsQuest can help

Our duo teams run this workflow from FASTQ or from your existing objects, and frequently re-analyze datasets during peer review. See our [single-cell RNA-seq analysis service](/services/single-cell-rna-seq-analysis/) for the full list of analyses, or read the [12 most common scRNA-seq mistakes](/insights/single-cell-rna-seq-mistakes/) we fix.

---
Source: https://omicsquest.com/insights/single-cell-rna-seq-analysis-best-practices/ | OmicsQuest, contact@omicsquest.com
