Back to Blog
SamtoolsNGSAlignment

Install samtools & bcftools with Conda (macOS Apple Silicon)

Install samtools and bcftools on an Apple Silicon Mac using an isolated conda env with conda-forge and bioconda, then verify with a real BAM smoke test.

SSSudipta SardarJuly 20, 20269 min read
Install samtools & bcftools with Conda (macOS Apple Silicon)

If you work with next-generation sequencing data, samtools and bcftools are two tools you will reach for constantly. samtools reads, sorts, indexes, and summarizes alignment files (SAM/BAM/CRAM), while bcftools calls and manipulates variants (VCF/BCF). Both are built on the same C library, htslib, and they are almost always installed together and pinned to the same version.

In this guide we install all three inside a single isolated conda environment on an Apple Silicon Mac. The whole point of the isolation is this: the exact build you need lives inside the env, pinned and reproducible, completely independent of your system Python or Homebrew. When a future project needs a different version, you make a new env instead of breaking this one.

Prerequisites

You need conda. If you have not set it up yet, follow our Miniconda on Apple Silicon guide first, then come back here. This walkthrough was run on:

  • Apple Silicon Mac (arm64), macOS 26.5.2
  • conda 25.5.1 with the fast libmamba solver (the modern default)

One important detail about recent conda: version 24.x and later gate the old defaults (Anaconda pkgs/main) channel behind a Terms-of-Service acceptance prompt. We sidestep that entirely by never touching defaults and installing only from conda-forge and bioconda.

TL;DR — copy-paste install

bash
conda create -n bu-samtools --override-channels \
  -c conda-forge -c bioconda \
  samtools=1.24 bcftools=1.24 htslib=1.24
conda activate bu-samtools

That is the whole install. The rest of this guide explains each piece, shows the real output, and helps you verify it worked.

Step by step

1. Create one isolated env for the tools

bash
conda create -n bu-samtools --override-channels \
  -c conda-forge -c bioconda \
  samtools=1.24 bcftools=1.24 htslib=1.24

A few things are deliberate here:

  • --override-channels plus explicit -c conda-forge -c bioconda tells conda to ignore any defaults channel in your global config. This is what keeps you clear of the conda Terms-of-Service prompt.
  • Channel order matters. conda-forge must come before bioconda, because bioconda is built on top of conda-forge and assumes that priority. Reverse them and you can get an unsolvable or subtly broken environment.
  • Pinning =1.24 on all three keeps samtools, bcftools, and htslib in lockstep and makes the env reproducible. Drop the pins if you always want the newest release.

On the test machine the solve and install finished in about 27 seconds. Here is the real (trimmed) output:

Channels:
 - conda-forge
 - bioconda
Platform: osx-arm64
Collecting package metadata (repodata.json): done
Solving environment: done

  added / updated specs:
    - bcftools
    - htslib
    - samtools

The following NEW packages will be INSTALLED:

  bcftools           bioconda/osx-arm64::bcftools-1.24-hf623529_1
  htslib             bioconda/osx-arm64::htslib-1.24-hd3c6ec9_0
  samtools           bioconda/osx-arm64::samtools-1.24-h36b3a25_1
  libdeflate         conda-forge/osx-arm64::libdeflate-1.25-hc11a715_0
  liblzma            conda-forge/osx-arm64::liblzma-5.8.3-h8088a28_0
  libcurl            conda-forge/osx-arm64::libcurl-8.21.0-h1359186_2
  ncurses            conda-forge/osx-arm64::ncurses-6.6-h1d4f5a5_0
  openssl            conda-forge/osx-arm64::openssl-3.6.3-hd24854e_0
  perl               conda-forge/osx-arm64::perl-5.32.1-7_h4614cfb_perl5
  gsl                conda-forge/osx-arm64::gsl-2.7-h6e638da_0
  ... (plus zlib, bzip2, c-ares, krb5 and other htslib dependencies)

real 26.81

Notice Platform: osx-arm64 and every package tagged osx-arm64. These are native Apple Silicon builds — no emulation involved. You can also see the expected supporting cast: libdeflate and liblzma for fast BAM/CRAM (de)compression, libcurl/openssl for htslib's remote (https/S3) access, ncurses for samtools tview, gsl and perl for some bcftools plugins and scripts.

2. Activate the env

bash
conda activate bu-samtools

The env's binaries only appear on your PATH once it is activated. If you ever see samtools: command not found, this is almost always the reason.

Apple Silicon note

For samtools, bcftools, and htslib, native osx-arm64 builds exist on bioconda at version 1.24, so no Rosetta is needed — bioconda began shipping Apple Silicon packages back in 2023. You can confirm your install is genuinely native:

bash
file $(which samtools)

A native build reports arm64; a Rosetta-emulated one would report x86_64.

Rosetta is only relevant for the occasional older bioconda tool that still lacks an arm64 build. In that case, create a separate env with CONDA_SUBDIR=osx-64 and pin it with conda config --env --set subdir osx-64. Never mix architectures inside one env — keep native and emulated tools in different environments.

Verify the install

Two quick checks: confirm the versions, then run a real end-to-end smoke test.

Versions

bash
samtools --version
bcftools --version

Real output from the test machine:

samtools 1.24
Using htslib 1.24
Copyright (C) 2026 Genome Research Ltd.
bcftools 1.24
Using htslib 1.24

The Using htslib 1.24 line matching on both tools is exactly what you want — it means samtools and bcftools are linked against the same htslib you pinned.

Smoke test: SAM to sorted BAM to index to flagstat

This exercises the real workflow. We write a tiny two-read SAM file, sort it into a BAM, index it, and summarize it:

bash
printf '@HD\tVN:1.6\tSO:coordinate\n@SQ\tSN:chr1\tLN:100\nr1\t0\tchr1\t1\t60\t4M\t*\t0\t0\tACGT\tIIII\nr2\t0\tchr1\t5\t60\t4M\t*\t0\t0\tGGCC\tIIII\n' > tiny.sam
samtools sort -O bam -o tiny.bam tiny.sam
samtools index tiny.bam
samtools flagstat tiny.bam

Real flagstat output:

2 + 0 in total (QC-passed reads + QC-failed reads)
2 + 0 primary
0 + 0 secondary
0 + 0 supplementary
0 + 0 duplicates
0 + 0 primary duplicates
2 + 0 mapped (100.00% : N/A)
2 + 0 primary mapped (100.00% : N/A)
0 + 0 paired in sequencing
0 + 0 read1
0 + 0 read2
0 + 0 properly paired (N/A : N/A)
0 + 0 with itself and mate mapped
0 + 0 singletons (N/A : N/A)
0 + 0 with mate mapped to a different chr
0 + 0 with mate mapped to a different chr (mapQ>=5)

Two reads, both mapped at 100 percent, and a tiny.bam.bai index created alongside the BAM. If you see that, your install is fully working.

Common errors & fixes

ErrorFix
CondaToSNonInteractiveError / prompt to accept Terms of Service for the defaults channelDon't use defaults at all — add --override-channels -c conda-forge -c bioconda to the create command, as shown above.
PackagesNotFoundError: samtools not available from current channelsMake sure you passed both -c conda-forge -c bioconda in that order. Native arm64 builds exist for 1.24; run conda update -n base conda and, if needed, conda clean -i to clear a stale channel cache.
Unsatisfiable / broken env when bioconda is listed before conda-forgeAlways order conda-forge then bioconda, and set strict priority: conda config --set channel_priority strict.
samtools: command not found after installYou forgot to activate: conda activate bu-samtools. Env binaries only appear on PATH once activated.
Illegal instruction: 4 or dyld/arch errors on Apple SiliconYou installed an osx-64 build under a mismatched setup. Recreate as native arm64 (the default on M-series).
Using htslib 1.xx mismatch after piecemeal installsInstall samtools/bcftools/htslib together, pinned to the same =1.24, in one env so conda links them against matching htslib.

This blog is grounded in a real run on an Apple Silicon Mac. The install command, version output, and flagstat output above are copied verbatim from that session. The individual error-and-fix rows in the table are documented behaviors from the conda and bioconda docs, not all reproduced on the test machine.

Managing the env

Update the tools within the env (drop pins to move to newer builds):

bash
conda activate bu-samtools
conda update --override-channels -c conda-forge -c bioconda samtools bcftools htslib

Snapshot the exact environment so a collaborator (or future you) can rebuild it:

bash
conda env export --from-history > bu-samtools.yml

Remove it entirely when you no longer need it:

bash
conda remove -n bu-samtools --all

For reference, the finished env measured about 207 MB on disk (measured with du -sh; because conda hardlinks shared packages, the incremental cost of an extra env is usually less) — small, self-contained, and safe to delete and recreate any time.

Next steps