Write biological sequences to files (FASTA, FASTQ, GenBank, EMBL) using Biopython Bio.SeqIO. Use when saving sequences, creating new sequence files, or outputting modified records.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Write biological sequences to files (FASTA, FASTQ, GenBank, EMBL) using Biopython Bio.SeqIO. Use when saving sequences, creating new sequence files, or outputting modified records.
tool_type
python
primary_tool
Bio.SeqIO
Version Compatibility
Reference examples tested with: BioPython 1.83+
Before using code patterns, verify installed versions match. If versions differ:
Python: pip show <package> then help(module.function) to check signatures
If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.
Write Sequences
"Write sequences to a file" -> Serialize SeqRecord objects into a formatted sequence file.
Python: SeqIO.write() (BioPython)
R: writeXStringSet() (Biostrings)
Governing Principle
The write is only as complete as the SeqRecord. Each format reads specific record fields and silently ignores the rest, so what survives a write is decided by which fields are populated before the call, not by the format string. FASTA serializes only id/description+seq; FASTQ additionally requires letter_annotations['phred_quality']; GenBank/EMBL additionally require . Populate the fields a format needs, or the write either drops data quietly (FASTA) or raises (FASTQ/GenBank).
annotations['molecule_type']
Required Import
from Bio import SeqIO
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
Core Functions
SeqIO.write() - Write Records to File
SeqIO.write(records, 'output.fasta', 'fasta')
records - Single SeqRecord, list, or iterator of SeqRecords
handle - Filename (string) or open file handle
format - Lowercase output format string
Returns the number of records written (integer)
record.format() - Get Formatted String
formatted = record.format('fasta')
The FASTA Header Trap (id vs description)
FASTA output is built from record.description, NOT record.id. The writer compares the first whitespace token of description to id: if they match it writes description as-is; otherwise it prepends id + a space. When a record is parsed from FASTA, description already leads with the id token, so a round trip is faithful. But when id and description are set independently, a stale id-like token inside the description gets duplicated, and older BioPython releases dropped the id entirely instead of prepending it.
record.id
record.description
Header written
seq1
seq1 kinase domain
>seq1 kinase domain (clean: description leads with id)
seq1
kinase domain
>seq1 kinase domain (id auto-prepended)
seq1
`` (empty)
>seq1 (id used as fallback)
seq1
gene7 kinase domain
>seq1 gene7 kinase domain (stale id duplicated)
To control the header exactly and stay robust across versions, make description begin with id + a space: description=f'{rec_id} kinase domain'. The FASTA writer wraps the sequence at 60 characters per line by default.
Format Field Requirements
Format
String
Record fields read
Hard requirement
FASTA
'fasta'
id/description, seq
none (header trap above)
FASTQ
'fastq'
seq, letter_annotations
phred quality scores
GenBank
'genbank' / 'gb'
seq, annotations, features
molecule_type
EMBL
'embl'
seq, annotations, features
molecule_type
Tab
'tab'
id, seq
none
Creating SeqRecord Objects
Goal: Construct in-memory records that carry the fields the target format requires.
Approach: Build a SeqRecord from a Seq plus id; add letter_annotations['phred_quality'] for FASTQ and annotations['molecule_type'] for GenBank/EMBL.
"Create a sequence record from scratch" -> Wrap a Seq in a SeqRecord with metadata.
Python: SeqRecord(Seq(...), id=...) (BioPython)
record = SeqRecord(Seq('ATGCGATCGATCG'), id='seq1', description='seq1 example sequence')
withopen('output.fasta', 'w') as handle:
SeqIO.write(records, handle, 'fasta')
withopen('output.fasta', 'a') as handle:
SeqIO.write(new_records, handle, 'fasta')
Write Modified Records via Generator
Goal: Transform sequences in memory and write the modified versions to a new file.
Approach: Parse input, map a transform over a generator, write the generator. Streaming avoids loading every record into RAM.
"Modify sequences and save" -> Parse records, transform each, write with SeqIO.write().
defuppercase_record(rec):
return SeqRecord(rec.seq.upper(), id=rec.id, description=rec.description)
records = SeqIO.parse('input.fasta', 'fasta')
modified = (uppercase_record(rec) for rec in records)
SeqIO.write(modified, 'output.fasta', 'fasta')
Write FASTQ with Quality Scores
FASTQ requires letter_annotations['phred_quality'] as a list of ints. letter_annotations is length-locked to len(seq): assigning a list whose length differs from the sequence raises. Set the sequence first, then the quality list of matching length.
When both phred_quality and solexa_quality keys are present, the writer uses Phred. Writing 'fastq-solexa' from a Phred-only record forces an on-the-fly lossy conversion (the scales diverge in the low-quality region) and emits a BiopythonWarning once any score reaches the high end (max quality >= ~62). For modern data, write plain 'fastq' (Sanger/Phred+33); only use 'fastq-solexa'/'fastq-illumina' when a tool explicitly demands that legacy encoding.
Write GenBank Format
GenBank and EMBL writing requires annotations['molecule_type'] (the alphabet that once carried this was removed in BioPython 1.78). Missing it raises on write.