Chatomics Field GuideWhat They Don't Teach You

Comparison · integration

Harmony vs Seurat CCA integration: Which One Should You Use?

One corrects the map, the other rewrites the territory, knowing which matters before you run your first FindMarkers call.

By Ming "Tommy" Tang, Director of Bioinformatics in Big Pharma · Reviewed September 2026 · 4 min read

The verdict

Default to Harmony. For the typical case here, exploratory clustering or reference-building where you don't know in advance whether every cell type is shared across batches, Harmony is the safer call. It never touches the expression matrix, so downstream differential expression and marker detection run on real values instead of a batch-corrected proxy. It's also far cheaper at scale, roughly 4 minutes on 30,000 cells versus 68 minutes on 500,000, using 30 to 200 times less runtime and 30 to 50 times less memory than anchor-based methods like MultiCCA in published benchmarks. Its batch-correction benchmark score edges out CCA (0.616 vs 0.607 in one published comparison), though that margin is thin enough that it shouldn't be the deciding factor on its own.

Reach for Seurat CCA integration when you already know the cell types are conserved across your datasets and the main source of variation is a batch-level expression shift, that's the scenario Seurat's own documentation calls out as CCA's sweet spot. It's also the right call when you specifically need the corrected expression values themselves, not just an aligned embedding, for example feeding a unified matrix into a visualization or a downstream tool that expects one integrated data slot. Don't reach for it when a large share of your cells are batch-specific or non-overlapping; that's where CCA's anchor-finding step over-merges distinct populations, and Seurat's own docs point toward RPCA, not CCA, as the conservative alternative in that case.

Harmony and Seurat's CCA integration solve the same problem, aligning cells from different batches so they cluster by biology instead of by which experiment they came from, but they operate on completely different parts of your data. Harmony works entirely inside PCA space: it takes the embedding you already computed, iteratively soft-clusters cells across batches, and nudges each cluster's per-batch centroids toward a shared center until batch separation collapses. It never opens the expression matrix.

CCA does the opposite. It treats each dataset as a matrix over the same genes, computes cross-covariance between them, and solves a generalized eigenvalue problem to find components where the two datasets correlate, essentially a paired PCA. It then finds mutual nearest neighbors ("anchors") between datasets in that shared space and uses those anchor pairs to compute correction vectors that get applied directly to expression values, producing a new, batch-corrected data slot.

That difference in where the correction lands drives almost everything else in this comparison: what you can safely use for differential expression afterward, how much time and memory the run costs, and how badly a batch of cells with no real counterpart in the other dataset gets mangled.

Head to head

CriterionHarmonySeurat CCA integrationEdge
What the correction touchesHarmony adjusts only the PCA embedding; the original counts and normalized expression matrix are never modified.Seurat CCA integration writes batch-corrected values into the `data` slot of a new integrated assay, replacing the normalized expression for downstream use in that assay.Harmony
Matters most for whatever you do after integration, not for the integration step itself.
Underlying statistical methodIterative soft clustering in PCA space: cells are repeatedly clustered across batches and per-batch cluster centroids are nudged together until batch separation collapses.Canonical correlation analysis: cross-covariance between datasets is decomposed via a generalized eigenvalue problem to find correlated components, then mutual nearest neighbors ('anchors') are identified in that space.Tie
Different mechanisms solving the same alignment problem; neither is inherently more correct.
Behavior with non-overlapping cell populationsPreserves biological variability better when a large fraction of cells are batch-specific or represent new/shifted states.Anchor-finding assumes shared biological states between datasets and over-merges distinct populations when a large proportion of cells don't overlap, per Seurat's own RPCA documentation.Harmony
Runtime at scaleRoughly 4 minutes on 30,000 cells, 68 minutes on 500,000 cells; 30 to 200 times faster than MultiCCA and MNN Correct in published benchmarks.Built on anchor-finding machinery similar to MultiCCA, one of the slow baselines Harmony is benchmarked against; no comparable runtime figures for CCAIntegration were found in the cited sources.Harmony
Memory footprint0.9GB at 30,000 cells, 7.2GB at 500,000 cells; 30 to 50 times less memory than Scanorama, MNN Correct, and Seurat MultiCCA.No direct memory figures for CCAIntegration in the cited sources, but MultiCCA, a related anchor-based method, is among the high-memory baselines Harmony is compared against.Harmony
Batch-correction benchmark scoreScored 0.616 in the SeuratIntegrate benchmark comparison.Scored 0.607 in the same benchmark, marginally behind Harmony.Harmony
The gap is small and comes from a single published comparison, not a universal ranking.
Documented sweet spotGeneral-purpose default suited to exploratory work and cases with unknown or partial overlap between batches.Explicitly recommended by Seurat's documentation when cell types are conserved across datasets but expression levels differ substantially between experiments.Seurat CCA integration
Downstream differential expression workflowBecause expression values are untouched, DE and marker detection run on the same assay you integrated from, no assay-switching step required.Because the integrated assay holds corrected values, you must explicitly switch back to the original (e.g. RNA) assay before running DE, a step that's easy to forget.Harmony
Integration into Seurat v5 workflowAvailable as method='HarmonyIntegration' inside IntegrateLayers(), alongside CCA, RPCA, FastMNN, and scVI, on the same Seurat object.Available as method='CCAIntegration' inside the same IntegrateLayers() function; it's also the original, most heavily documented integration method in Seurat's own tutorials.Tie
Both are first-class options in Seurat v5; the choice is about the data, not tooling friction.

Use Harmony when

  • A large fraction of cells are batch-specific or represent new or shifted states you don't want forced into alignment with another batch.
  • You're integrating a large atlas, hundreds of thousands of cells, where runtime and memory budgets matter.
  • You plan to run differential expression or marker detection downstream and want to test on untouched expression values.
  • You're not certain in advance whether cell types are fully shared across your batches.
  • You want a fast default inside Seurat v5's IntegrateLayers without adding a separate corrected-assay bookkeeping step.

Use Seurat CCA integration when

  • Cell types are known to be conserved across datasets, and the main difference between batches is an expression-level shift, not different populations.
  • You're building a reference atlas where strong, consistent alignment across datasets matters more than preserving subtle per-batch expression differences.
  • You need the corrected expression matrix itself, not just an aligned embedding, for visualization or a downstream tool that expects one integrated data slot.
  • Your datasets are small enough that CCA's runtime and memory cost aren't a practical constraint.
  • You want to stay inside Seurat's original, most heavily documented integration tutorial for troubleshooting support.

Switching between them

Switching between the two inside Seurat v5 is mostly a one-line change, method='HarmonyIntegration' versus method='CCAIntegration' inside IntegrateLayers(), but what comes out differs in ways that affect every step after. Harmony adds a new dimensional reduction (e.g. harmony) to your object and leaves every assay untouched, so FindNeighbors/FindClusters just point at the new reduction and DE continues to run on your original assay. CCA integration produces both a new reduction and a modified expression assay with corrected values in its data slot; you need to explicitly set DefaultAssay() back to your original assay before running FindMarkers or any DE test, since testing on the corrected slot conflates batch correction with your biological comparison. CCAIntegration also takes a normalization.method argument that must match how you actually normalized your data (LogNormalize vs SCTransform); a mismatch isn't caught automatically. Don't treat the batch-correction benchmark scores (0.616 for Harmony vs 0.607 for CCA) as portable thresholds, they come from one published comparison on one dataset composition, not a universal cutoff for judging your own integration quality.

Pitfalls with either

  • Running differential expression directly on Seurat CCA's integrated `data` slot instead of switching back to the RNA assay first, since those corrected values are meant for clustering and visualization, not statistical testing; fix by setting DefaultAssay() to your original assay before FindMarkers.
  • Treating Harmony's edge in one benchmark (0.616 vs 0.607) as proof it always beats CCA, when the margin is thin and specific to a single published comparison; fix by checking whether that benchmark's batch structure resembles yours before trusting the score.
  • Integrating two datasets that share no real biological overlap with either method and expecting clean clusters, when Seurat's own documentation says integration isn't appropriate if datasets are completely distinct; fix by checking cluster composition per batch before running integration, not after.
  • Assuming consistent clusters between Harmony and CCA mean downstream comparisons will also agree, when a direct comparison showed differential expression results between treatments diverged substantially; fix by validating DE hits with an orthogonal method like pseudobulk before drawing conclusions.
  • Defaulting to CCA as the 'safe' choice when populations are heavily non-overlapping, when Seurat's docs point to RPCA, not CCA, as the conservative alternative in that scenario; fix by checking the RPCA integration vignette before assuming CCA is conservative enough.

Questions people ask

Does Harmony change my gene expression values?

No. Harmony only adjusts the PCA coordinates it's handed, correcting the embedding, not the counts or normalized expression matrix. You can run differential expression and marker detection on your original expression values after integration without worrying that Harmony altered them.

Why do Harmony and Seurat CCA agree on clusters but disagree on differential expression?

A direct user comparison (Seurat GitHub issue #2533) found cluster identity and conserved marker genes were consistent between the two methods, but differential expression results between treatment groups differed substantially. Clustering is robust to how the correction was done; DE testing is much more sensitive to whether the values being tested were touched by the integration algorithm.

Which method is faster on a large dataset?

Harmony scales from about 4 minutes on 30,000 cells to 68 minutes on 500,000 cells, using 30 to 200 times less runtime than MultiCCA and MNN Correct in published benchmarks, plus 30 to 50 times less memory across that same size range. Seurat's CCA-based integration wasn't benchmarked at that scale in these sources, but it shares anchor-finding machinery with MultiCCA, one of the slower, memory-heavy baselines Harmony was compared against.

Should I use RPCA instead of CCA when my datasets don't fully overlap?

If a large share of your cells are batch-specific, Seurat's own documentation recommends RPCA over CCA as the more conservative option, since cells in different biological states are less likely to be forced into false alignment. Harmony is also a reasonable choice in that scenario, since it's built to preserve variability from non-overlapping cell states rather than merge them.

Can I switch between Harmony and CCA in the same Seurat v5 workflow?

Yes. Seurat v5's IntegrateLayers() function supports both as method arguments, along with RPCA, FastMNN, and scVI, on the same Seurat object. Swapping method='HarmonyIntegration' for method='CCAIntegration' doesn't require rebuilding your object, but the two produce different outputs, a corrected reduction versus a corrected expression assay, so downstream steps need to change accordingly.

Related pages

Related reading on the blog

Sources

  1. How CCA alignment and cell label transfer work in Seurat — Explains the covariance/eigenvalue mechanism behind CCA and anchor finding.
  2. Fast, sensitive, and accurate integration of single cell data with Harmony — Source for Harmony's algorithm description and runtime/memory benchmarks.
  3. Introduction to scRNA-seq integration • Seurat — Documents when CCA integration is recommended.
  4. Fast integration using reciprocal PCA (RPCA) • Seurat — Source for CCA's over-merging risk and RPCA as the conservative alternative.
  5. Integrative analysis in Seurat v5 • Seurat — Documents the IntegrateLayers methods available in Seurat v5.
  6. SeuratIntegrate: an R package to facilitate the use of integration methods with Seurat — Source of the 0.616 vs 0.607 batch-correction benchmark scores.
  7. Comparison of results between Harmony and Seurat (GitHub Issue #2533) — Source for the cluster-consistent-but-DE-differs finding.