A de Bruijn assembler never aligns whole reads against each other. Instead every read is chopped into overlapping k-length substrings (k-mers); each k-mer becomes a directed edge from its first k−1 letters to its last k−1 letters. Stitching every read's k-mers together this way builds one graph for the whole dataset, and reconstructing the genome becomes graph theory: find a walk that uses every edge exactly once (an Eulerian path). A base miscalled by the sequencer creates a k-mer nobody else supports — a short dead-end "tip" or a parallel "bubble" the path must route around.
nodes = distinct (k−1)-mers observed
edges = k-mers (node[i..i+k-2] → node[i+1..i+k-1])
Eulerian path exists ⇔ graph connected AND
every node has in-degree = out-degree, except
≤1 node with out−in=+1 (start) and ≤1 with in−out=+1 (end)
- k-mer size (k) — larger k carries more sequence per edge and resolves short repeats, but needs deeper coverage to bridge every join.
- Coverage — how many overlapping reads feed the graph; low coverage leaves nodes with no edge out, breaking the path.
- Sequencing error rate — each miscalled base mints a spurious k-mer, which shows up as a red tip or bubble the traversal must skip past.
- Assembler path — toggle the pulse that walks the highest-confidence route through the graph, the way a real assembler traces contigs out of a de Bruijn graph.
Real-world relevance: de Bruijn graphs are exactly how short-read assemblers (Velvet, SPAdes, most Illumina pipelines) reconstruct genomes at scale — the "many small fragments" outcome real assemblies hit almost always traces back to unresolved bubbles and tips just like the ones visualized here.