Pulse - Value Added
FRACTIONAL CRO · MARYLAND-BASED, NATIONWIDE · $0→$200M

Kory White

RevOps & Revenue Leadership

Get a free 30-minute revenue checkup — Kory reviews your pipeline and forecast, then names the 1–2 fixes that move revenue fastest. 25 yrs scaling teams $0→$200M.

Free 30-min revenue checkup →
Hire a Fractional CROHow We Help?LinkedInRésuméCRO Syndicate
← Library
Knowledge Library · pulse-tech-stacks
13/13 Gate✓ IQ Certified10/10?

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch

Tech StacksA Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch
📖 3,553 words🗓️ Published Jul 23, 2026
Direct Answer

A genome assembly and variant calling pipeline uses Nextflow to orchestrate steps, Conda to pin exact tool versions, and AWS Batch to run jobs on elastic Spot compute. Raw FASTQ reads are trimmed, assembled or aligned to a reference, deduplicated, called into variants with GATK, then annotated and reported — reproducibly, at roughly $1–3 per human genome.

What this stack is and why each layer exists

A bioinformatics pipeline is a directed sequence of command-line tools where each step consumes files and emits files, and the whole chain must be re-runnable months later with byte-identical results. Three problems break that promise, and this stack solves one each.

Nextflow is the workflow engine. You write processes in a Groovy-based DSL2 syntax, and Nextflow handles dataflow between them via channels rather than explicit file paths. Its most practically important feature is the work directory: every process execution gets its own hashed subdirectory under work/, containing symlinked inputs, the exact command run (.command.sh), stdout, stderr, and exit code. This makes -resume genuinely reliable — Nextflow hashes the process script plus input file contents and skips anything unchanged. On a 200-sample cohort where step 6 of 9 failed, -resume restarts only from step 6, saving hours of recompute. Compare this to a bash script, where a mid-run failure means either starting over or hand-editing the script to skip completed steps.

Conda solves the dependency problem. Genomics tools have brutal dependency graphs: GATK needs a specific Java version, BWA needs a compiler toolchain, Samtools needs htslib, and several tools have conflicting requirements for zlib or Python. The bioconda channel packages several thousand bioinformatics tools with resolved dependencies. You declare an environment.yml pinning exact versions — bwa=0.7.17, samtools=1.19, gatk4=4.5.0.0, fastp=0.23.4 — and Conda builds an isolated environment. Nextflow supports this natively: add conda 'bioconda::bwa=0.7.17' to a process directive and Nextflow creates and caches that environment automatically.

AWS Batch provides the compute. Genome assembly is embarrassingly heterogeneous: read trimming is I/O-bound and needs 2 vCPUs, alignment is CPU-bound and scales to 16–32 cores, de novo assembly of a large genome can demand 256 GB–1 TB of RAM for a few hours, and variant calling is somewhere in between. Owning hardware sized for the worst step means paying for idle capacity 95% of the time. AWS Batch matches each job to an instance type from a compute environment, launches it, runs the container, and terminates it. Nextflow's awsbatch executor submits each process execution as a separate Batch job with its own resource request.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 1

The combination matters more than any single piece. Nextflow alone still leaves you fighting tool installs. Conda alone still leaves you writing orchestration by hand. AWS Batch alone gives you compute with no dataflow model. Together you get a pipeline that a colleague can clone, run with nextflow run main.nf -profile awsbatch, and reproduce your exact variant calls.

The step-by-step process from FASTQ to annotated VCF

The canonical short-read pipeline has seven stages. Assembly-first and reference-first workflows diverge in the middle but share the ends.

Quality control and trimming. FastQC profiles the raw reads; fastp or Trimmomatic removes adapter sequence and low-quality tails. Typical settings trim bases below Phred Q20 and discard reads under 36 bp. On a healthy 30x human WGS sample you expect to lose 2–8% of bases here. Losing more than 15% signals a library prep or sequencer problem worth investigating before spending compute downstream. This step needs 2–4 vCPUs and finishes in 10–20 minutes.

Alignment or assembly. For a reference-based workflow, BWA-MEM or minimap2 aligns reads to the reference genome (GRCh38 for human), producing a SAM stream piped directly to samtools sort to avoid writing an enormous intermediate. Expect >95% alignment rate for human WGS against GRCh38; under 85% usually means contamination or the wrong reference. For de novo assembly — bacterial isolates, non-model organisms, or anything without a good reference — SPAdes handles bacterial genomes in 30–90 minutes on 16 cores, while Flye or hifiasm assemble long reads into contigs. Assembly quality is judged by N50, total assembly length versus expected genome size, and BUSCO completeness scores; a good bacterial assembly lands under 100 contigs with N50 above 100 kb.

Duplicate marking. PCR duplicates inflate apparent read depth and bias allele fractions. Picard MarkDuplicates or samtools markdup flags them. Duplicate rates of 5–15% are normal for PCR-based libraries; above 25% suggests over-amplification from low input DNA.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 2

Base quality score recalibration. GATK BaseRecalibrator plus ApplyBQSR corrects systematic sequencer error patterns using known variant sites (dbSNP, the 1000 Genomes indel set) as a mask. This adds 30–60 minutes per sample and is worth it for clinical work; many research pipelines skip it for high-quality modern data.

Variant calling. GATK HaplotypeCaller performs local de novo reassembly around active regions rather than naive pileup counting, which is why it handles indels well. Run it in GVCF mode (-ERC GVCF) so samples can be joint-genotyped later without recalling. Split by chromosome or by interval list and run intervals in parallel — this is where Nextflow earns its keep, turning a 12-hour serial call into a 1-hour fan-out across 24 concurrent jobs. Alternatives: DeepVariant for higher accuracy on some benchmarks at greater compute cost, bcftools mpileup for speed on simple cases, and Strelka2 for somatic calling.

Joint genotyping and filtering. GenomicsDBImport consolidates GVCFs; GenotypeGVCFs produces the multi-sample VCF. Then filter — VQSR if you have 30+ WGS samples to train on, hard filters otherwise (typical hard filters: QD < 2.0, FS > 60.0, MQ < 40.0 for SNPs). Expect roughly 4–5 million variants per human genome, of which about 4–5% are novel relative to dbSNP.

Annotation and reporting. SnpEff or VEP adds functional consequence predictions. MultiQC aggregates every tool's log into a single HTML report — this is the artifact humans actually look at.

Costs, runtimes, and resource sizing

Real numbers matter more than architecture diagrams when you are defending a compute budget.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 3

Human whole genome, 30x coverage (~90 GB of FASTQ). End-to-end wall clock on AWS Batch with reasonable parallelism is 4–8 hours per sample. Aggregate compute is roughly 40–80 vCPU-hours. On c6i or m6i On-Demand instances at typical us-east-1 rates that lands somewhere in the $4–10 range per sample; on Spot at a 60–80% discount, roughly $1–3. Storage adds up separately: 90 GB FASTQ plus a ~60 GB CRAM (or ~120 GB BAM) plus intermediates. Using CRAM instead of BAM cuts alignment storage roughly in half at the cost of needing the reference to decode.

Human whole exome, 100x coverage (~10 GB FASTQ). Under an hour of wall clock, a few vCPU-hours, cents to low single-digit dollars on Spot. Exomes are where you prototype.

Bacterial de novo assembly. SPAdes on a 5 Mb genome with 100x coverage: 30–90 minutes on 16 vCPUs and 64 GB RAM. Cost per isolate on Spot is well under a dollar. This is why microbial labs run hundreds of isolates without a budget conversation.

Large eukaryotic de novo assembly. This is the outlier that breaks naive sizing. Assembling a multi-gigabase plant or animal genome can need 500 GB–1 TB of RAM for 12–48 hours. You are looking at x2iedn or similar memory-optimized instances, and a single assembly can cost more than a hundred human resequencing samples. Budget it as a project, not a per-sample line item.

Sizing rules that hold up in practice. Give BWA-MEM 8–16 vCPUs and about 1 GB RAM per thread plus the reference index (roughly 6 GB for GRCh38). Give MarkDuplicates 8–16 GB heap and fast local scratch — it is I/O-bound and benefits from instance store NVMe. Give HaplotypeCaller 4 vCPUs and 8–16 GB per interval shard; it does not scale well past 4 threads, so parallelize by interval instead of by thread. Set Nextflow's errorStrategy &#39;retry&#39; with memory { 16.GB * task.attempt } so a job that OOMs gets retried with more memory rather than killing the run.

Cost controls that actually move the number. Spot instances are the single biggest lever — 60–90% off On-Demand, and because Nextflow retries interrupted tasks, interruptions cost you a restarted task rather than a failed run. Set maxRetries 3 and use errorStrategy { task.exitStatus in [143,137,104,134,139] ? &#39;retry&#39; : &#39;finish&#39; } to distinguish Spot reclamations from real failures. Second: S3 lifecycle policies. Raw FASTQ should move to Glacier Instant Retrieval or Deep Archive after 30–90 days; intermediate BAMs should be deleted entirely once the VCF is validated. Teams routinely spend more on forgotten S3 intermediates than on compute. Third: clean the Nextflow work/ directory after a successful run — it holds every intermediate from every task and is often larger than all your final outputs combined. Fourth: use S3 Intelligent-Tiering on the results bucket and tag every Batch job with a project tag so Cost Explorer can attribute spend.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 4

Where teams get this wrong

Treating the work directory as disposable and then discovering it isn't. -resume only works if work/ still exists and the input files still hash the same. Teams clean work/ to save storage, then need to resume after a downstream failure and find they have to rerun everything. Decide explicitly: keep work/ until the run is validated, then delete it in one deliberate step.

Unpinned Conda environments. Writing bioconda::gatk4 without a version means the environment resolves differently depending on when you build it. Six months later the same pipeline produces different variant calls and nobody can explain why. Pin every package to an exact version, commit the environment.yml, and for anything approaching regulated work, export the fully-solved lock file with conda list --explicit. Better still, use containers (Docker/Singularity via wave or a pinned image digest) for the final production version — Conda pins the packages you named, but a container pins the entire filesystem.

Wrong reference genome, or mixed references. Aligning to hg19 and then annotating with a GRCh38 database silently produces garbage coordinates. Worse: GRCh38 comes in analysis-set and full-assembly variants, with and without ALT contigs, and BWA behaves differently on ALT-aware references unless you run the postalt script. Fix the reference bundle once, store it in S3, reference it by an immutable path, and record its checksum in the pipeline output.

Over-parallelizing HaplotypeCaller by thread instead of by interval. Giving one HaplotypeCaller job 32 threads yields poor scaling and wastes most of those cores. Split the genome into 20–50 intervals and run 20–50 four-core jobs. On AWS Batch this is nearly free to do and cuts wall clock dramatically.

Ignoring the AWS Batch compute environment ceiling. The default max vCPUs on a compute environment is often set low. Nextflow submits 200 jobs, Batch queues them behind a 256-vCPU cap, and the run takes ten times longer than expected while everyone stares at a progress bar. Check maxvCpus, check your account's EC2 service quotas for the instance families you requested, and check that your Spot capacity strategy is SPOT_CAPACITY_OPTIMIZED rather than SPOT_PRICE_CAPACITY_OPTIMIZED if you care more about interruption rate than the last few percent of savings.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 5

Skipping the QC report because the pipeline exited zero. A successful exit code means the tools ran, not that the data is usable. A sample with 40% duplicates, 60% alignment rate, or 8x effective coverage will produce a VCF that looks perfectly normal and is scientifically worthless. Gate on the MultiQC metrics: alignment rate, mean coverage, duplicate rate, insert size distribution, and Ti/Tv ratio (expect roughly 2.0–2.1 for WGS, 3.0–3.3 for exomes — a low Ti/Tv means false-positive-heavy calls).

Data egress surprises. Compute costs get scrutinized; transfer costs don't, until the bill arrives. Keep the pipeline in the same region as the S3 bucket, avoid cross-region reads of the reference bundle, and pull results down once rather than repeatedly. For a lab moving terabytes, egress can exceed compute.

Building it from scratch when nf-core exists. nf-core is a curated collection of community Nextflow pipelines with standardized structure, testing, and documentation. nf-core/sarek covers germline and somatic variant calling; nf-core/mag covers metagenome assembly. Starting from a maintained pipeline and customizing is nearly always faster than writing your own, and you inherit the community's bug fixes.

Decision framework: choosing the right path for your data

The three decisions that determine everything downstream are: assemble or align, which caller, and which executor.

Assemble or align to a reference. If a high-quality reference exists for your organism and you care about variation relative to it, align — it is faster, cheaper, and better supported. Assemble when there is no good reference, when the sample is a novel organism or a metagenome, when you need structural information the reference obscures (large insertions, plasmids, novel sequence), or when the sample is bacterial and assembly is cheap enough to just do.

A Bioinformatics Pipeline: Genome Assembly and Variant Calling with Nextflow, Conda, and AWS Batch — figure 6

Which variant caller. GATK HaplotypeCaller is the default for germline short reads and the best-documented path. DeepVariant often edges it out on indel accuracy, especially for PacBio HiFi and Oxford Nanopore data, at meaningfully higher compute cost. bcftools mpileup is dramatically faster and adequate for high-coverage bacterial haploid calling. For somatic/tumor calling, GATK Mutect2 or Strelka2 — do not use a germline caller on tumor data; the ploidy and allele-fraction assumptions are wrong.

Which executor. Nextflow's local executor is right for exome-scale prototyping on a laptop or a single large EC2 box. A Slurm or SGE executor is right if you already have an HPC cluster with idle capacity — on-prem hardware you have already bought is cheaper than Spot. AWS Batch is right when workload is bursty, when you need 100+ concurrent jobs occasionally rather than constantly, or when you have no cluster. Kubernetes via Nextflow's k8s executor is right if your organization already runs Kubernetes and wants one scheduler for everything. AWS Batch is generally lower-friction than EKS for this workload because you are not managing a cluster.

A practical sequencing of the build. Start with an nf-core pipeline running locally on a downsampled test dataset — nf-core ships -profile test configurations that run in minutes. Get it green locally, then add an AWS Batch profile in nextflow.config pointing at a compute environment, an S3 work directory, and a job queue. Run one real sample, inspect the Batch console for right-sized instances and the Nextflow trace file for per-task CPU and memory utilization, and adjust the resource labels. Only then scale to the full cohort. The trace file (-with-trace) and the execution report (-with-report) tell you exactly which processes are over- or under-provisioned; a process requesting 64 GB and peaking at 9 GB is money on fire.

On monitoring at scale. Once you are past roughly 100 runs a month, the Seqera Platform (the commercial home of Nextflow) gives you centralized run history, per-run cost attribution, and the ability to launch pipelines without shell access — useful when bench scientists need to run pipelines themselves. Below that volume, the built-in HTML report plus CloudWatch logs plus Cost Explorer tags cover it.

Reproducibility as a deliverable. For any work that will be published, audited, or submitted to a regulator, the reproducibility artifacts are part of the output, not overhead. Pin the pipeline to a git tag (nextflow run org/pipeline -r v2.1.0), pin the container digests, archive the environment.yml and solved lock file, store the trace and report files alongside the VCF, and record the reference genome checksum. A run you cannot reproduce is a run you cannot defend — and in commercial genomics, where sequencing services carry real revenue implications and clients audit methods, an unreproducible result is a liability rather than a deliverable.

Related questions

Can I run this pipeline without AWS?

Yes. Nextflow's executor is a configuration switch. The same pipeline runs on Slurm, SGE, LSF, Kubernetes, Google Cloud Batch, Azure Batch, or a single machine's local executor by changing nextflow.config. Process definitions and Conda environments stay identical.

Should I use Conda or Docker containers?

Conda is faster to iterate on and easier to modify. Containers are more reproducible because they pin the entire filesystem, not just named packages. Common practice: develop with Conda, ship production with pinned container digests. Nextflow supports both via process directives.

How much coverage do I actually need?

For human germline SNP calling, 30x is the accepted standard. Exomes need 100x because capture efficiency is uneven. Somatic calling in tumors typically wants 80–100x or higher due to subclonal variants and normal contamination. Bacterial assembly is comfortable at 50–100x.

What does -resume actually cache on?

Nextflow hashes the process script text, the input file contents (or metadata, depending on the caching mode), and the process directives. Any change to any of these invalidates that task and everything downstream of it. The cache lives in the work/ directory and .nextflow/ cache database.

Is de novo assembly ever needed for human samples?

Rarely for clinical resequencing, but yes for population-specific reference building, for resolving complex structural variation and highly polymorphic regions like HLA, and for pangenome work. Long-read assembly of human genomes is increasingly practical but still costs substantially more than reference-based calling.

FAQ

How long does a full 30x human genome take end to end?

Roughly 4–8 hours of wall clock on AWS Batch with interval-parallelized variant calling, against 20–40 hours if run serially on a single machine. The variable is how aggressively you shard HaplotypeCaller and how much Batch capacity is available. Trimming and alignment are typically the longest single steps; joint genotyping across a large cohort can exceed both.

What is the most common cause of a failed Nextflow run on AWS Batch?

IAM and networking, by a wide margin. The Batch job role needs S3 read/write on both the work bucket and the data bucket, the compute environment needs a subnet with outbound internet access or the right VPC endpoints (S3, ECR, CloudWatch Logs), and the ECS instance role needs its standard permissions. Second most common is out-of-memory kills on MarkDuplicates or assembly steps.

Do I need to rebuild Conda environments on every run?

No. Set conda.cacheDir to a persistent location — an S3 path or a shared filesystem — and Nextflow reuses solved environments across runs. Without this, every job rebuilds the environment, adding minutes per task and hammering the Anaconda servers. On AWS Batch, mounting an EFS volume or baking environments into a custom AMI both work.

How do I handle patient data compliance on this pipeline?

Run Batch inside a VPC with no public subnets, use VPC endpoints for S3 so data never traverses the internet, enable SSE-KMS encryption on all buckets with a customer-managed key, turn on CloudTrail and S3 access logging, and restrict the Batch job role to the minimum bucket prefixes. Nextflow's trace and log files serve as the provenance record. Confirm your specific obligations with your compliance team — the technical controls are necessary but not sufficient.

What is the difference between the assembly output and the variant calling output?

Assembly produces contigs or scaffolds in FASTA — the reconstructed sequence itself, judged by N50 and completeness. Variant calling produces a VCF listing positions where the sample differs from a reference, with genotypes and quality scores. Assembly answers "what is this sequence"; variant calling answers "how does this sample differ from the reference."

Should I write my own pipeline or start from nf-core?

Start from nf-core unless you have a genuinely unusual workflow. nf-core/sarek handles germline and somatic variant calling; nf-core/mag handles metagenome assembly; others cover RNA-seq, ATAC-seq, and more. They ship tested modules, standardized configs, AWS Batch profiles, and a test profile that runs in minutes. Fork and customize rather than rebuild.

Sources

flowchart TD S["A Bioinformatics Pipeline: Genome Asse"] S --> N0["What this stack is and why each layer "] N0 --> N1["The step-by-step process from FASTQ to"] N1 --> N2["Costs, runtimes, and resource sizing"] N2 --> N3["Where teams get this wrong"]

Related on PULSE

Download:
Was this helpful?  
⌬ Apply this in PULSE
Gross Profit CalculatorModel margin per deal, per rep, per territory