Chatomics Field GuideWhat They Don't Teach You

Comparison · differential expression

DESeq2 vs limma-voom: Which One Should You Use?

Counts with a GLM or log-CPM with precision weights: the right pick flips once your sample size crosses from a handful of replicates into the hundreds.

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

The verdict

For the standard bulk RNA-seq experiment most readers of this site are running, three or four replicates per condition comparing a treatment to a control, DESeq2 is the right default. Its negative binomial model was built for exactly this regime, it performs slightly better than limma-voom with TMM normalization at 6 to 12 samples per group, and it ships with dedicated fold-change shrinkage (lfcShrink with apeglm) that makes downstream ranking and volcano plots more trustworthy when counts are noisy.

Switch to limma-voom once your sample size stops looking like a typical lab experiment and starts looking like a cohort study. Past roughly a hundred samples per group, DESeq2's assumptions are documented to produce inflated false discovery rates, and DESeq2's own developers point people toward limma-voom at that scale. The same applies if your design has several covariates, batch terms, or interactions across a large number of samples: limma's linear-model machinery fits that faster and more reliably than DESeq2's GLM. If your comparison is really between huge, near-identical groups, TCGA subtype comparisons or thousands of single cells, skip both and reach for a Wilcoxon rank-sum test instead.

DESeq2 and limma-voom start from the same raw count matrix but take opposite routes to a p-value. DESeq2 keeps counts as counts: it fits a negative binomial GLM directly on the integers, using median-of-ratios size factors and dispersion estimates borrowed across genes to stabilize variance at low counts. limma-voom instead converts counts to log2-CPM, estimates the mean-variance trend across that transformed data, and turns it into a precision weight for every single observation. Those weights are what let ordinary linear-model code, originally built for microarrays, work correctly on RNA-seq counts.

The practical consequence is where each one is strong. Negative binomial modeling on raw counts is the right tool when you have few samples and each one carries a lot of statistical weight; DESeq2 was built in the era of 3 vs 3 experiments and still handles that regime well. voom's approach assumes the log-CPM values are close to normally distributed once weighted, an assumption that gets better as sample size grows and gets shakier when it's small.

Normalization differs too, even though both correct for library size. DESeq2's size factors come from geometric-mean ratios per gene; limma-voom normalizes with edgeR's TMM before the voom transform. On well-behaved data the two rarely disagree by much, but conflating them, for example reusing DESeq2 size factors inside an edgeR pipeline, is a common source of confusion that has nothing to do with either method being wrong.

Head to head

CriterionDESeq2limma-voomEdge
Statistical modelFits a negative binomial GLM directly on raw integer counts, with gene-wise dispersions shrunk toward a fitted trend.Converts counts to log2-CPM, estimates the mean-variance trend, and generates a precision weight per observation so limma's linear-model and empirical Bayes code applies to RNA-seq data.Tie
Different statistical philosophies, both peer-reviewed and widely used. The choice should follow sample size and design, not a belief that one model is inherently more correct.
Performance at small n (3 vs 3, 6 vs 6)Built for and validated on small experiments; a benchmark found DESeq2 performs slightly better than voom with TMM normalization at 6 or 12 samples per group.voom's assumption that log-CPM values are approximately normal after weighting holds worse with few samples, since raw count distributions dominate at small n.DESeq2
Performance at large n (hundreds of samples)Shows exaggerated false positives and FDR inflation in datasets spanning 100 to 1,376 samples as its negative binomial assumptions break down.Recommended by DESeq2's own developers for datasets with hundreds of samples, and holds up more reliably at that scale.limma-voom
Speed on large datasetsScales linearly with gene count but slows noticeably with complex designs and very large sample counts.Runs much faster than GLM-based methods once sample counts reach into the hundreds, though it is memory-limited and single-threaded.limma-voom
NormalizationMedian-of-ratios size factors, computed from the geometric mean of each gene's counts across samples, assuming most genes are not differentially expressed.TMM normalization (via edgeR) applied before the voom transform, resting on the same core assumption but a different estimator.Tie
Low-count filtering defaultsApplies independent filtering automatically, tuned to your chosen alpha, which can silently change which genes are tested if you change alpha between runs.No automatic filtering; you're expected to remove low-count genes yourself (e.g. with edgeR's filterByExpr) before running voom.Tie
DESeq2's automation is convenient until you don't realize alpha is doing double duty as both the significance cutoff and the filtering threshold.
Fold-change shrinkageHas a dedicated shrinkage step, lfcShrink() with apeglm, built specifically for ranking and visualizing noisy low-count genes.No direct equivalent; moderated t-statistics from eBayes() stabilize variance but don't shrink the fold-change estimate itself.DESeq2
Complex design matrices at scaleA single comprehensive model is statistically and computationally more efficient than repeated separate analyses, but fitting slows as both sample count and design complexity grow.Linear-model machinery handles multi-covariate, batch-term and interaction designs efficiently even across hundreds of samples.limma-voom
Input requirementsRequires raw, un-normalized integer counts; feeding it TPM or pre-normalized values breaks the negative binomial variance model.Also starts from raw counts loaded into a DGEList, but the linear model itself runs on log-CPM transformed, weighted values rather than the counts.Tie
Ecosystem and interoperabilityTight integration with tximport (Salmon/kallisto import) and apeglm; the standard path for a typical bulk RNA-seq project.Shares its linear-model core with limma's microarray and proteomics workflows, and pairs naturally with edgeR (DGEList, calcNormFactors) and Glimma for visualization.Tie

Use DESeq2 when

  • You're running a typical small bulk RNA-seq experiment, 2v2, 3v3, or up to about 12 samples per group, the regime DESeq2 was built for.
  • You need effect-size shrinkage (lfcShrink with apeglm) to rank genes or draw a clean volcano plot when low-count genes are noisy.
  • Your design is a straightforward two-group or simple factorial comparison, not a large cohort with many covariates.
  • You want an opinionated, batteries-included pipeline that handles size factors, dispersion estimation and low-count filtering for you without hand-building a design matrix.
  • You're importing counts via tximport from Salmon or kallisto and want the single most documented path from counts to results.

Use limma-voom when

  • You're comparing hundreds of samples per group, the scale where DESeq2's FDR is documented to inflate.
  • Your design matrix has multiple covariates, batch terms, or interactions across a large cohort.
  • Runtime matters and you need a fit that completes much faster than a GLM-based method on a large dataset.
  • You're already working in an edgeR or limma ecosystem, or need to analyze RNA-seq alongside microarray or proteomics data in one linear-model framework.
  • You're on memory-constrained, single-threaded hardware where voom's log-CPM linear model outperforms GLM fitting at scale.

Switching between them

Switching between the two isn't a drop-in swap. DESeq2 works from a DESeqDataSet built around a matrix, colData and a design formula; limma-voom starts from an edgeR DGEList, runs calcNormFactors() for TMM, then voom() produces an EList with weights that feeds lmFit() and eBayes(). Don't reuse DESeq2's median-of-ratios size factors inside the edgeR/limma pipeline, recompute normalization from raw counts with calcNormFactors() instead. DESeq2 filters low-count genes automatically via independent filtering tied to your alpha; limma-voom has no equivalent, so replicate that filtering yourself with something like edgeR's filterByExpr() before voom(), or the mean-variance trend voom fits gets distorted by genes that should never have been tested. Fold-change numbers aren't comparable across the two either: DESeq2's apeglm-shrunken log fold changes sit on a different scale than limma's unshrunken model coefficients, so a fold-change cutoff tuned for one output shouldn't be reused for the other. Finally, DESeq2 derives its design matrix from a formula and infers reference levels from factor order, while limma requires you to build model.matrix() and any contrasts explicitly, so double-check reference levels and contrasts by hand when you migrate a DESeq2 analysis to limma-voom.

Pitfalls with either

  • Feeding DESeq2 pre-normalized values like TPM or CPM instead of raw integer counts breaks its negative binomial variance model, so always pass raw counts and let DESeq2 compute its own size factors.
  • Trusting DESeq2's FDR at face value on cohort-scale data with hundreds of samples ignores documented inflation at that scale, so switch to limma-voom or a Wilcoxon rank-sum test for large, homogeneous group comparisons.
  • Running voom() without filtering out low-count genes first lets those genes distort the mean-variance trend the whole model depends on, so filter with edgeR's filterByExpr() before voom, not after.
  • Comparing DESeq2's shrunken log fold changes directly against limma's unshrunken model coefficients treats two different scales as one, so note which shrinkage method, if any, produced a given number before setting a fold-change cutoff.
  • Concluding DESeq2 and limma-voom fundamentally disagree when results diverge usually points to a workflow mistake rather than a real model conflict, so audit the input matrix, filtering step and design matrix before blaming the tool.
  • Using DESeq2 or limma-voom for single-cell marker detection between large groups of cells wastes their strengths, since Wilcoxon-based methods like Seurat's FindAllMarkers() are faster and better suited to that comparison.

Questions people ask

Is DESeq2 or limma-voom more accurate for differential expression?

Neither is universally more accurate. DESeq2's negative binomial model performs slightly better at small sample sizes, 6 to 12 per group, while limma-voom holds up better and avoids FDR inflation once you're working with hundreds of samples. Pick based on your sample size and design complexity, not a general accuracy claim.

When should I switch from DESeq2 to limma-voom?

Switch once your comparison groups reach into the hundreds of samples, or your design includes multiple covariates, batch terms and interactions that make a single DESeq2 model slow to fit. DESeq2's own developers recommend limma-voom at that scale because of documented false-positive inflation.

Can DESeq2 and limma-voom give different results on the same data?

Yes, but when the workflows are done correctly they generally converge on similar conclusions. Most reported disagreements trace back to mismatched input data, missing low-count filtering, or an inconsistent design matrix rather than a fundamental conflict between the models.

Do I need to normalize my counts before running DESeq2 or limma-voom?

Both tools want raw, un-normalized integer counts as input; each computes its own normalization internally, median-of-ratios for DESeq2, TMM for limma-voom's voom step. Pre-normalizing with TPM or CPM before handing counts to either tool breaks their variance models.

Which tool should I use for TCGA-scale bulk RNA-seq comparisons?

Neither is the first choice. For very large, homogeneous groups a Wilcoxon rank-sum test is faster and avoids the FDR inflation both DESeq2 and edgeR show at that scale. If you want a GLM-style tool anyway, limma-voom scales better than DESeq2 for cohort-sized comparisons.

Related pages

Related reading on the blog

Sources

  1. Analyzing RNA-seq data with DESeq2 — Official DESeq2 methods, lfcShrink and independent filtering documentation
  2. voom: precision weights unlock linear model analysis tools for RNA-seq read counts — Foundational voom paper describing the log-CPM transform and precision weights
  3. RNA-seq analysis is easy as 1-2-3 with limma, Glimma and edgeR — Practical limma-voom plus edgeR plus Glimma workflow
  4. A large-sample crisis? Exaggerated false positives by popular differential expression methods — Study documenting exaggerated false positives in DESeq2 and edgeR at 100 to 1,376 samples
  5. Benchmarking RNA-seq differential expression analysis methods using spike-in and simulation data — Benchmark showing DESeq2's slight edge over voom with TMM at 6 or 12 samples per group
  6. RNA seq differential expression analysis for large sample size — Bioconductor discussion recommending limma-voom for hundreds of samples and comparing speed
  7. Different results between Limma and DESEQ2 for Differential Expression Analysis — Explains that apparent DESeq2 vs limma disagreements usually trace back to workflow issues
  8. Building a biologically meaningful design matrix for limma/voom in a large RNASeq experiment — Guidance on complex design matrices for limma-voom at scale