How to Convert FASTA to FASTQ: A Step-by-Step Guide

By Dr. Zubair Khalid, DVM, MS, PhD ·

How to Convert FASTA to FASTQ: A Step-by-Step Guide

By the end of this guide you will be able to take a nucleotide FASTA file and produce a FASTQ file that every standard parser accepts, with no truncation, no length mismatches, and no silent corruption. You will also know which placeholder quality value to assign, how to prove the output is structurally correct, and when the whole exercise is a bad idea.

You need a terminal, a text editor, and one of two things: awk (present on every Linux and macOS system) or seqtk. For verification you will want seqkit, which ships as a dependency-free binary for Linux, macOS, and Windows and is built specifically for FASTA and FASTQ manipulation [1]. Nothing else is required. No Python environment, no compiler, no reference genome.

The conversion itself is not the hard part. The hard part is that FASTA contains no quality information, so any FASTQ you produce contains invented data. This guide is mostly about managing that fact responsibly.

What FASTA and FASTQ Actually Store

FASTA: sequence and nothing else

FASTA is a plain-text format built from two element types. A header line starts with a greater-than sign (>) and carries an identifier plus optional free-text description. Sequence lines follow, and they may wrap across as many lines as the writer chose. There is no quality data, no fixed line count, and no required line width.

That simplicity is why FASTA is everywhere. Reference genomes, coding sequence sets, protein databases, and multiple sequence alignments are all distributed as FASTA. In proteomics, a protein FASTA file is a required input for essentially every search engine, and its absence is one of the recurring reasons published datasets cannot be reanalyzed [2]. The format also absorbs extensions. DRAMP 5.0 introduced a variant called FASTS that appends SMILES structure strings to FASTA annotation lines so that non-natural residues and chemical modifications survive in a single text file [3]. FASTA survives because it is boring.

FASTQ: sequence plus a per-base confidence score

FASTQ keeps the sequence and adds one thing: a quality string with one character per base. Each record uses four lines.

@read1 sample=A
ACGTACGTACGTACGT
+
IIIIIIIIIIIIIIII

Line 1 starts with @ and holds the identifier and description. Line 2 is the sequence. Line 3 starts with + and may repeat the header. Line 4 is the quality string, and its length must equal the sequence length exactly.

FASTQ is the native output of basecallers and sequencers. On Oxford Nanopore instruments, raw electrical signal is stored separately in POD5 files, with the open-source SLOW5 and BLOW5 formats positioned as alternatives to the older FAST5 container [4]. The basecaller reads that signal and emits reads, and those reads are written as FASTQ. A published MinION analysis of a multidrug-resistant Escherichia coli strain shows the chain explicitly: raw FAST5 reads were basecalled with Albacore and then converted to both FASTA and FASTQ with Poretools before assembly [5]. Basecalled reads exist as FASTQ first and as FASTA only after someone deliberately strips the quality.

The conversion is one-way in information terms

FASTQ to FASTA is lossy in a controlled way. You delete line 4 and change @ to >, and the sequence is unchanged. FASTA to FASTQ is the reverse direction but not the inverse operation. You must manufacture line 4 from nothing. The sequence comes back byte-identical, but the quality data does not exist and never did.

FeatureFASTAFASTQ
Header character>@
Lines per record2 or more, sequence may wrap4, fixed
Sequence line widtharbitraryconventionally one line
Per-base qualityabsentrequired, length must match sequence
Typical contentsgenomes, proteins, alignments, assembled contigsraw or trimmed sequencing reads
Effect of converting to the other formatquality permanently discardedquality fabricated, not recoverable

Decide What You Have Before You Convert

Not every FASTA should become a FASTQ. Run through this list first, because the most common conversion mistake happens before any command is typed.

What your FASTA containsShould you convert?Why
Basecalled reads exported as FASTAYes, with a conservative placeholderThese were FASTQ once, and a downstream tool refuses FASTA input
Assembled contigs or a draft genomeNoThere are no reads and no per-base quality to represent
Reference genome or transcriptomeNoTools that need it expect FASTA, and fake reads mislead variant callers
Protein sequencesNoFASTQ is defined for nucleotide alphabets, and protein quality has no meaning
A multiple sequence alignment with gap charactersNo, unless you degap it first- and . are not valid FASTQ sequence characters
Coding sequences with stop codons written as *No, unless you remove the ** is not a nucleotide and will break parsers

If you are working from public short-read data, check whether the FASTQ already exists before converting anything. RNA-seq protocols built on the SRA Toolkit download reads and pass them through quality checking with FastQC and adapter trimming with Trimmomatic before alignment, which means the FASTQ is normally the starting point rather than a derived product [6].

How to Convert FASTA to FASTQ Step by Step

The workflow below is the one to use when you want to understand and control every byte. It uses only awk for the conversion and seqkit for verification.

Step 1. Inspect the input file

Look at the first few lines and count records.

head -4 reads.fa
grep -c '^>' reads.fa
awk '/^>/{n++} !/^>/{if(length($0)>0) c++} END{print n" records, "c" non-empty sequence lines"}' reads.fa

Expected output for a small two-record file:

>read1 sample=A
ACGTACGTAC
GTACGT
>read2
TTTTAAAA
2
2 records, 3 non-empty sequence lines

The mismatch between record count and sequence line count tells you the file is wrapped. That is legal FASTA and the reason a naive line-by-line converter fails.

Also check for Windows line endings, which leave a carriage return at the end of every line and produce quality strings with invisible trailing bytes.

file reads.fa
awk '/\r$/{n++} END{print n+0" lines end with CR"}' reads.fa

If the second command prints anything above zero, strip the carriage returns before proceeding.

sed -i 's/\r$//' reads.fa

Step 2. Flatten and clean the FASTA

Convert to one sequence line per record, remove gaps, and force uppercase. SeqKit does all three in one pass.

seqkit seq -w 0 -g -u reads.fa > reads.clean.fa
  • -w 0 sets line width to zero, meaning no wrapping. Every sequence becomes a single line.
  • -g removes gap characters (- and .), which are illegal in a read.
  • -u uppercases the sequence. Soft-masked lowercase is valid FASTA but some downstream tools treat it inconsistently.

Confirm the flattening worked.

awk '/^>/{n++} !/^>/{if(length($0)>0) c++} END{print n" records, "c" sequence lines"}' reads.clean.fa

For a well-formed file the two numbers are now equal.

Step 3. Pick a placeholder quality value

This is the only decision in the process that involves judgment. The quality string is ASCII-encoded Phred, so the character you choose sets the claimed error probability for every base. The table in the Phred section below gives the arithmetic. The practical rule:

  • Use I (Phred 40) when the sequences genuinely came from high-accuracy short-read data and you simply lost the quality file.
  • Use 5 (Phred 20) when you want a mid-range value that will survive most quality filters without being absurd.
  • Do not use ! (Phred 0) unless you intend for every read to be discarded.
  • Do not use I for nanopore or other long-read data, where per-base accuracy is lower and Q40 is not a credible claim.

Step 4. Convert with awk

This script handles wrapped FASTA, strips stray whitespace, and writes a valid four-line record for every entry.

awk -v q='I' '
function rep(c, n,   s, i) { s = ""; for (i = 0; i < n; i++) s = s c; return s }
/^>/ {
  if (seq != "") printf "@%s\n%s\n+\n%s\n", header, seq, rep(q, length(seq))
  header = substr($0, 2)
  seq = ""
  next
}
{
  gsub(/[ \t\r]/, "", $0)
  seq = seq $0
}
END {
  if (seq != "") printf "@%s\n%s\n+\n%s\n", header, seq, rep(q, length(seq))
}
' reads.clean.fa > reads.fastq

Save it as a file if you will reuse it.

cat > fa2fq.awk <<'EOF'
function rep(c, n,   s, i) { s = ""; for (i = 0; i < n; i++) s = s c; return s }
/^>/ {
  if (seq != "") printf "@%s\n%s\n+\n%s\n", header, seq, rep(q, length(seq))
  header = substr($0, 2)
  seq = ""
  next
}
{
  gsub(/[ \t\r]/, "", $0)
  seq = seq $0
}
END {
  if (seq != "") printf "@%s\n%s\n+\n%s\n", header, seq, rep(q, length(seq))
}
EOF

awk -v q='I' -f fa2fq.awk reads.clean.fa > reads.fastq

Expected output for the example input, shown with head -8:

@read1 sample=A
ACGTACGTACGTACGT
+
IIIIIIIIIIIIIIII
@read2
TTTTAAAA
+
IIIIIIII

The header text after the identifier is preserved verbatim. Note that many downstream tools truncate the read name at the first whitespace, so read1 sample=A becomes read1 internally. That is normal and consistent, but it means the description field is not a reliable place to store sample identity.

Step 5. Convert with seqtk

seqtk is the conventional one-liner. Its seq subcommand has an option to write a constant fake quality character.

seqtk seq -F 'I' reads.clean.fa > reads.fastq

If your input is gzip-compressed, seqtk reads it directly.

seqtk seq -F 'I' reads.clean.fa.gz > reads.fastq

Check seqtk seq usage on your installed version if the -F flag is rejected, since option sets differ between releases. The awk version above has no such dependency and behaves identically across platforms.

Step 6. Check the four-line structure

Every record must have a @ on line 1 of the block, a + on line 3, and a sequence and quality of equal length.

awk 'NR%4==1 && substr($0,1,1)!="@" {print "bad header at line " NR}' reads.fastq
awk 'NR%4==3 && substr($0,1,1)!="+" {print "bad plus line at line " NR}' reads.fastq
awk 'NR%4==0 {print "total records: " NR/4; exit}' reads.fastq

Clean files print only the record count. Any other line means the file is malformed and every downstream tool will fail in a different, confusing way.

Step 7. Check sequence and quality lengths

This is the check that catches the two most common corruptions: a wrapped sequence that was not flattened, and a quality string built from the wrong length variable.

awk '
NR%4==1 {id=$0}
NR%4==2 {slen=length($0)}
NR%4==0 {
  if (length($0) != slen)
    printf "length mismatch at %s: seq=%d qual=%d\n", id, slen, length($0)
}
' reads.fastq

No output means every record is internally consistent. Add a summary line to confirm the check actually ran over all records.

awk 'END{print NR/4" records checked"}' reads.fastq

Step 8. Summarize with SeqKit

seqkit stats gives a compact audit of the file and, for FASTQ input, reports quality-derived columns.

seqkit stats reads.fastq

The output is a table with one row per file.

file         format  type  num_seqs  sum_len  min_len  avg_len  max_len  Q20(%)  Q30(%)  AvgQual  GC(%)
reads.fastq  FASTQ   DNA          2       24        8     12.0       16   100.0   100.0     40.0   33.3

The Q20(%) and Q30(%) columns will read 100.0 whenever the placeholder is at or above Phred 20, because every base carries the same constant score. That is expected, and it is also the reason those columns stop being informative after a conversion.

Use -a for the fuller statistic set, including quartiles and N50.

seqkit stats -a reads.fastq

Step 9. Compress and record provenance

FASTQ is roughly twice the size of the equivalent FASTA sequence content, since it carries an extra quality line plus two structural lines per record. Compress with a parallel gzip if available.

pigz -p 8 reads.fastq

Write a small note next to the file stating that the quality values are synthetic, which character was used, and the command that produced it. Institutional data layers that deliver sequencing files to downstream users rely on exactly this kind of metadata to keep file identity and provenance intact across projects [7]. A one-line README costs nothing and prevents a future analyst from treating AvgQual 40.0 as a measurement.

Phred Scores: What the Quality String Really Encodes

A Phred quality score Q maps to an estimated per-base error probability P through a base-10 logarithm.

Q = -10 * log10(P)
P = 10^(-Q/10)

The character stored in the FASTQ file is that score plus an ASCII offset of 33 for modern data.

character_code = Q + 33
CharacterASCIIPhred QError probabilityReads as
!3301.0 (1 in 1)every base wrong, tools discard
#3520.63very poor
+43100.1 (1 in 10)poor
553200.01 (1 in 100)common filter cutoff
?63300.001 (1 in 1,000)common filter cutoff
I73400.0001 (1 in 10,000)high-quality placeholder
J74410.00008above typical short-read range

A worked calculation makes the consequence concrete. For a 150 bp read, the expected number of erroneous bases is 150 P. At a constant Q40 that is 150 0.0001 = 0.015 errors per read, so roughly one read in 67 carries an error. At Q20 it is 150 * 0.01 = 1.5 errors per read. Same sequence, wildly different implied data quality, purely from the character you chose.

Two encoding pitfalls deserve names. Modern FASTQ uses Phred+33, meaning ASCII 33 corresponds to Q0. Legacy Solexa and early Illumina pipelines used Phred+64, where ASCII 64 corresponds to Q0. If a Phred+64 file is read as Phred+33, every score appears 31 points higher than it is. This matters when you inherit old files, not when you generate new ones, since anything you write with the scripts above is Phred+33 by construction.

Options and Parameters That Matter

Tool and flagWhat it doesWhen to change it
awk -v q='I'Sets the placeholder quality characterLower it for long-read or low-accuracy data
seqtk seq -F 'I'Writes a constant fake quality characterUse 5 for a mid-range placeholder
seqkit seq -w 0Disables sequence line wrappingKeep as is, FASTQ needs unwrapped sequence
seqkit seq -gRemoves gap charactersRequired if the source is an alignment
seqkit seq -uUppercases the sequenceOptional, improves consistency
seqkit stats -aFull statistics including quartiles and N50Use when you need length distributions
seqkit fq2faConverts FASTQ back to FASTAUse for the reverse direction, drops quality
pigz -p 8Parallel gzip compressionMatch thread count to available cores

Common Mistakes and Limitations

Mistakes that produce structurally invalid files

Leaving the FASTA wrapped. A script that assumes two lines per record will emit a sequence line longer than its quality line whenever the source wraps. The downstream error is usually a length mismatch reported at some arbitrary record number. Fix it with seqkit seq -w 0 or the flattening awk logic above.

Forgetting the plus line. The + is not optional. Omitting it shifts every subsequent record by one line and produces a file that fails on record two rather than record one.

Leaving carriage returns in place. A FASTA edited on Windows carries \r at every line end. The quality string then ends with an invisible character, and length checks fail by one. Strip with sed -i 's/\r$//' before converting.

Passing an alignment straight through. Gap characters - and . are not nucleotides. A converted alignment produces FASTQ records that some parsers accept and others reject, which is worse than a clean failure. Degap first with seqkit seq -g.

Converting protein FASTA. The alphabet is wrong, the quality concept does not apply, and tools expecting nucleotide FASTQ will either error or silently misinterpret the data.

Mistakes that produce valid but misleading files

Assigning Phred 0. Every read fails every quality filter. If your pipeline silently drops all reads and reports zero, this is the first thing to check.

Assigning Phred 40 to long reads. Nanopore and other long-read data do not carry Q40 per-base accuracy. Inflating the scores causes variant callers and consensus tools to treat every base as equally trustworthy.

Trusting the Q20 and Q30 columns afterward. They will read 100 percent because the scores are constant. Any quality-based statistic computed after conversion describes your placeholder, not the sequencing run.

Collapsing duplicate identifiers. FASTA permits duplicate headers and FASTQ tools frequently do not. Duplicate read names cause silent record collisions during sorting, pairing, or conversion to BAM, where sequencing data are normally stored after alignment [8]. Check for duplicates before converting.

Assuming the description field survives. Many tools keep only the first whitespace-delimited token of the header. Put sample and barcode information somewhere structured, not in the FASTA description.

Writing an unstable output the second time. If you convert the same FASTA twice with different placeholder characters, you get two different files with the same name. Record which command produced which file.

Hard limitations

The fabricated quality cannot be recovered, corrected, or validated. Any analysis that depends on per-base confidence, including quality-score recalibration, error-rate modeling, and likelihood-based variant calling, is invalid on a converted file. The sequence content is exact. Everything about confidence is invented.

FASTA to FASTQ is not reversible in the sense that matters. Converting back with seqkit fq2fa gives you the original sequence, but the quality line is gone forever unless you kept the source file.

The format itself is not the bottleneck. Metagenomics workflows illustrate the broader problem: the number of file formats a pipeline must handle keeps growing, and each conversion point is a place where data can be dropped or mislabeled [9]. Keeping a small number of canonical formats and converting only at defined boundaries is easier to maintain than converting in every direction.

Library behavior reinforces this. Biopython's SeqIO.write refuses to write a FASTQ record that has no quality annotation, raising an error of the form ValueError: No suitable quality scores found in letter_annotations of SeqRecord (id=read1). That refusal is a feature. It forces you to make the placeholder decision explicitly rather than inheriting a default.

When FASTA to FASTQ Is the Wrong Move

If you have raw signal data and need real quality scores, do not convert a FASTA. Basecall the raw data directly. The raw files, whether POD5 on an Oxford Nanopore instrument or an alternative container, hold the signal that a basecaller converts into reads with genuine per-base quality, which is exactly the path taken in published nanopore workflows where basecalled FAST5 files were converted to FASTA and FASTQ with Poretools [4][5].

If you have a reference genome, the answer is also no. Reference FASTA is an input format for aligners, not a read format. Turning a chromosome into a fake read with uniform Q40 will confuse every tool that expects reads to be shorter than the reference.

If you have a protein FASTA, the answer is no for a different reason. Protein FASTA is a database format. Its role in a pipeline is to be searched against, and its absence from a deposited dataset is enough to block reanalysis entirely [2].

If you have assembled contigs and a tool insists on FASTQ, the honest options are to find a tool that accepts FASTA or to state clearly in your methods that qualities were synthetic. Converting silently and reporting Q30 statistics afterward is the one approach that produces a published result nobody can reproduce.

Frequently Asked Questions

Can I convert FASTA to FASTQ without losing information?

No. The sequence survives exactly, but FASTA has no quality data to carry across, so every quality score in the output is invented. The sequence is preserved and the confidence information is fabricated.

What quality score should I assign when converting FASTA to FASTQ?

Use I (Phred 40) for high-accuracy short-read data and 5 (Phred 20) when you want converted reads to pass typical filters without claiming unrealistic accuracy. Never use !, which encodes Phred 0 and causes every read to be discarded.

Why does my converted FASTQ fail quality filtering?

The placeholder character is almost always the cause. A Phred 0 placeholder fails every filter, and a very low placeholder fails most. Check the character used in the conversion command before investigating the sequences.

Does the conversion preserve FASTA header lines?

The full header text after the > is preserved and the leading character becomes @. Many downstream tools keep only the first whitespace-delimited token as the read identifier, so put important metadata in a structured file rather than the header description.

Can I convert a multi-line FASTA file to FASTQ?

Yes, but you must flatten it first. Either run seqkit seq -w 0 or use a converter that accumulates sequence lines until it sees the next header. Line-by-line converters produce length mismatches on wrapped input.

Is FASTA to FASTQ conversion reversible?

Only in one direction. Converting FASTQ to FASTA discards quality permanently, and converting FASTA to FASTQ invents quality that was never there. A round trip returns the original sequence and a fabricated quality string, not the original data.

Which file is smaller, FASTA or FASTQ?

FASTA is smaller. For identical sequence content, FASTQ adds a quality line of the same length as the sequence plus a plus line per record, which roughly doubles the file before compression.

Can I convert a protein FASTA file to FASTQ?

No. FASTQ is defined for nucleotide sequences with per-base quality scores, and protein data has neither the right alphabet nor a meaningful quality value. Protein FASTA is a search database format, not a read format.

Sources

  1. SeqKit: A Cross-Platform and Ultrafast Toolkit for FASTA/Q File Manipulation.
  2. Preventing Proteomics Data Tombs Through Collective Responsibility and Community Engagement.
  3. DRAMP 5.0: an update integrating sequence and structure in a novel FASTS format for AI-driven design of antimicrobial peptides.
  4. The enduring advantages of the SLOW5 file format for raw nanopore sequencing data.
  5. MinION nanopore sequencing identifies the position and structure of bacterial antibiotic resistance determinants in a multidrug-resistant strain of enteroaggregative Escherichia coli.
  6. Streamline Protocol for Bulk-RNA Sequencing: From Data Extraction to Expression Analysis.
  7. MetaServe: a lightweight, metadata-aware governance and delivery layer for pre-publication research omics data.
  8. Atlantool: a command line tool to retrieve DNA and RNA sequencing reads from BAM files by the read identifier.
  9. CAMP: a modular metagenomics analysis system for integrated multistep data exploration.