How to Codon Optimize a Vaccine Construct for E. coli Expression: Codon Usage, CAI and Restriction Sites

Codon optimization rewrites a vaccine construct’s DNA so that E. coli reads it with abundant tRNAs, without changing a single amino acid. The workflow is five steps: reverse translate the protein, adapt codons to a well sampled host table, check CAI and GC3, scan for restriction sites your vector needs free, then add cloning overhangs.
This is the last in-silico step of a reverse vaccinology project. By this point you have screened epitopes, assembled them into a construct with linkers and an adjuvant, docked it against a Toll-like receptor and simulated that complex in GROMACS. What you have is a protein sequence. What a wet lab needs is a DNA insert. Everything below is how you get from one to the other, and how you check you did it correctly.
What does codon optimization actually do, and what does it not do?
The genetic code is redundant. Leucine has six codons, arginine has six, and the protein is identical whichever you pick. Cells are not indifferent to the choice, because the tRNA pools that read those codons are not equally abundant. A gene evolved in a human pathogen is written in the codon dialect of its original host. Hand that same DNA to E. coli and the ribosome will stall wherever it hits a codon whose tRNA is scarce.
Codon optimization is a tRNA-abundance problem, not a translation-accuracy problem. The ribosome will still make the right protein. It will just make it slowly, and slow translation is associated with truncation and inclusion-body formation. So be honest about the ceiling here: optimization changes the odds of good expression. It does not guarantee expression, and any page that promises you a specific fold-increase in yield is guessing.
Three things codon optimization will not fix: a construct that is insoluble because of its own hydrophobic core, a protein that needs eukaryotic glycosylation, and a construct that was badly designed in the first place. If your epitopes never passed antigenicity and toxicity screening, no amount of codon work rescues it.
Which codon usage table should you optimize against?
This is the decision that most tutorials get wrong, and it is worth getting right before you touch a tool.
The standard free source is the Codon Usage Database maintained by Yasukazu Nakamura at Kazusa. Its home page states its data source plainly: NCBI-GenBank Flat File Release 160.0, dated June 15 2007, covering 35,799 organisms and 3,027,973 complete protein coding genes. That freeze date is not trivia. The tables you are about to optimize against are close to two decades old. For a deeply sequenced workhorse like E. coli that is perfectly adequate, because its codon usage was already well characterised in 2007. For an obscure host it is a real limitation, and you should say so in your dissertation rather than pretend the number is current.
Now the trap. Search that database for E. coli and you get dozens of entries of wildly different quality. The entry literally labelled Escherichia coli K12, at species=83333, is built from 14 CDS (5,122 codons). Fourteen genes is not a codon usage table. It is a rounding error, and a frequency drawn from it is meaningless.
Use a well sampled entry instead. Three real options, with the counts read off the database:
| Kazusa entry | species id | CDS | Codons | Coding GC | Use it? |
|---|---|---|---|---|---|
| Escherichia coli K12 | 83333 | 14 | 5,122 | 52.35% | No. Far too few genes. |
| Escherichia coli W3110 | 316407 | 4,332 | 1,372,057 | 51.93% | Yes. K-12 lab strain, genome scale. |
| Escherichia coli (species level) | 37762 | 8,087 | 2,330,943 | 47.30% | Only if you want a strain-agnostic average. |
Those last two disagree in ways that matter. W3110 uses AGA at 2.0 per thousand; the pooled species-level entry uses it at 7.1 per thousand, because it mixes lab strains with pathogenic isolates that have different GC content. Pick the entry that matches the strain you will actually transform, and name it in your methods section. “We used the E. coli codon usage table” is not a reproducible statement.
How do you reverse translate the construct?
Reverse translation turns your amino acid sequence into DNA by choosing one codon per residue. The free, citable tool is EMBOSS backtranseq on the EBI Job Dispatcher. Paste the construct in FASTA, choose a codon usage table, submit.
There is exactly one setting on that form and it is the one students get wrong. The EBI service exposes 108 codon usage tables, and its default is Ehuman.cut, Homo sapiens. If you paste a construct and press submit without touching the dropdown, you will get a human-optimized gene and never notice. For an E. coli host you want Eecoli.cut (Escherichia coli K12) or Eecoli_high.cut, the highly expressed subset.
How much does that dropdown matter? Take the single most frequent codon for each amino acid in Homo sapiens (Kazusa lists 93,487 CDS and 40,662,582 codons for it) and compare against E. coli W3110. Ten of the twenty amino acids have a different winner. Two are severe:
| Amino acid | Human top codon | Human freq (per 1,000) | Same codon in E. coli W3110 | E. coli top codon |
|---|---|---|---|---|
| Proline | CCC | 19.8 | 5.5 | CCG (23.4) |
| Arginine | AGA | 12.2 | 2.0 | CGC (22.3) |
| Lysine | AAG | 31.9 | 10.3 | AAA (33.6) |
| Glutamate | GAG | 39.6 | 18.0 | GAA (39.7) |
| Leucine | CTG | 39.6 | 53.1 | CTG (53.1), agrees |
AGA and AGG are the classic rare arginine codons that force labs onto tRNA-supplementing strains. Leaving the human default selected sprinkles them through your construct.
Want the guided, hands-on version?
Our live Molecular Modeling & MD Simulations cohort bootcamp takes you from zero to running real docking and MD workflows, with a portfolio project for your grad-school applications.
Why is “always pick the most frequent codon” the wrong method?
It is the method every free tool implements, and it produces a sequence no synthesis vendor wants.
Here is a worked example you can reproduce. Take an 89-residue illustrative construct built from the usual vocabulary (an EAAAK adjuvant linker, AAY and GPGPG epitope linkers, a C-terminal His-tag), back translate it three ways against the real Kazusa tables above, and measure the GC content overall and at the third codon position:
| Method | Overall GC | GC3 (third position) | Rare codons introduced |
|---|---|---|---|
| A. Human table, top codon only | 67.79% | 94.38% | 6 x CCC, 5 x AGA |
| B. E. coli W3110, top codon only | 61.42% | 69.66% | none |
| C. E. coli W3110, frequency-weighted sampling with a floor of 8 per 1,000 | 54.68% | 52.81% | none |
All three encode the identical protein. Method A is what happens when you leave the dropdown alone. Method B fixes the rare codons but pins GC3 near 70%, because the single most frequent E. coli codon is G-ending or C-ending for most amino acids, so choosing only winners stacks G and C at every third base. Method C keeps the host preference as a probability distribution instead of a rule, and lands GC3 at 52.81%, close to the 51.93% coding GC of the W3110 genome itself.
Long high-GC stretches are what make a gene hard to synthesize and hard to sequence. Do not chase a target number you read on a blog. Read the GC limits your chosen synthesis vendor publishes on their own order page, and design to those.
What does CAI actually measure, and should you maximise it?
The Codon Adaptation Index comes from Sharp and Li, “The codon Adaptation Index, a measure of directional synonymous codon usage bias, and its potential applications”, Nucleic Acids Research 15(3):1281-1295, 1987. Read the abstract before you quote a CAI value at anyone, because it defines the two things students misunderstand.
First, the reference set. In the authors’ words, the index “uses a reference set of highly expressed genes from a species to assess the relative merits of each codon”. CAI is not an absolute property of your DNA. It is a comparison against a chosen set of genes. Change the reference set and the number changes. A CAI reported without naming its reference set is uninterpretable, and this is the single most common defect in student dissertations at this step.
Second, the strength of the claim. The paper says the index “may also give an approximate indication of the likely success of heterologous gene expression”. Approximate indication. Not a prediction, not a guarantee, and certainly not a threshold you must clear. Treat CAI as a sanity check that says “this sequence is written in something like the host’s dialect”, not as a score to maximise. Driving CAI toward 1.0 means collapsing every amino acid onto one codon, which is exactly method B above, and you already saw what that does to GC3.
To compute CAI and GC yourself with no web form, Biopython’s Bio.SeqUtils module is the reproducible route. CodonAdaptationIndex(sequences) builds the relative adaptiveness table from a reference set you supply and its .calculate(sequence) method returns the CAI as a float. Because you pass the reference genes in explicitly, your methods section can state exactly what the number was computed against. For GC, gc_fraction(seq) returns a value between 0 and 1, and GC123(seq) returns a tuple of the total plus the GC at first, second and third codon positions, which is the GC3 column in the table above. There is also an .optimize() method that rewrites a sequence with preferred codons only; the docs describe it accurately as generating “DNA sequences with only preferred codons”, so it reproduces method B and inherits method B’s GC problem.
How do you check restriction sites before ordering the insert?
Your insert has to go into a vector, and the enzymes you cut with must not cut inside the insert. This check happens before you order, because a synthesized gene with an internal site is scrap.
Run the optimized DNA through NEBcutter, which reports every site in the sequence with the enzymes that cut once, twice or not at all. Pick your cloning pair from the enzymes that do not appear. Then confirm the vector’s own polylinker with Addgene’s vector database and open the map in the free read-only SnapGene Viewer. Note that SnapGene Viewer is a viewer; the editing features are in the paid product.
The important thing to understand is that internal sites are created by your codon choices, not by your protein. Same construct as above, same host table, same sampling rules, only a different random draw: one draw produced no sites for any of NdeI (CATATG), XhoI (CTCGAG), BamHI (GGATCC), EcoRI (GAATTC), HindIII (AAGCTT), NcoI (CCATGG) or SalI (GTCGAC). Another draw produced a HindIII site. It falls at the lysine-leucine junction at residues 19 and 20, where the sampler happened to draw AAG for the lysine and CTT for the leucine. AAG followed by CTT reads AAGCTT, and the site spans the codon boundary between two perfectly reasonable individual choices.
The fix is a silent recode: swap that lysine codon to AAA (which W3110 uses at 33.6 per thousand, more often than AAG at 10.3 anyway), the protein is unchanged, and the site is gone. This is why the restriction scan is a check on the specific DNA you are about to order, and why it has to be repeated every time you regenerate the sequence.
What is the full five-step workflow?
- Reverse translate. Paste the construct into EMBOSS backtranseq at the EBI and set the codon table to
Eecoli.cutorEecoli_high.cut. Do not accept theEhuman.cutdefault. - Adapt to the host. Compare your codons against a well sampled table (W3110, species 316407). Replace anything sitting near the bottom of the frequency list for its amino acid. Sample in proportion to frequency rather than always taking the winner.
- Check the numbers. Compute CAI against a named reference set, and GC plus GC3 with
GC123. Record both, with the reference set named. - Scan for restriction sites. Run NEBcutter, cross-check the vector polylinker in Addgene, silently recode any site that clashes.
- Verify and add overhangs. Translate the final DNA back with Expasy Translate and confirm it is character-for-character your original construct. Only then append the cloning overhangs and, if you are validating clones by PCR, design primers with Primer-BLAST.
Step 5 is the highest-value minute in this entire process. A single dropped or added base shifts the frame, and every downstream number stays superficially plausible while the protein is nonsense. Translate it back. Always.
Which codon optimization tools are actually usable right now?
| Tool | What it does | Input | Output | Cost | The catch |
|---|---|---|---|---|---|
| Codon Usage Database | Host codon frequency tables | Organism name | Frequency per 1,000 and GC by position | Free | Data frozen at GenBank release 160.0 (2007); many entries have too few CDS to trust |
| EMBOSS backtranseq (EBI) | Reverse translation | Protein FASTA | DNA FASTA | Free | Defaults to the human table; one codon per amino acid only |
| Biopython Bio.SeqUtils | CAI, GC, GC123, preferred-codon rewrite | Sequences in Python | Floats and Seq objects | Free | You must supply the CAI reference set yourself |
| NEBcutter | Restriction site map | DNA sequence | Cut sites and enzyme lists | Free | Tells you what cuts, not what your vector needs |
| Expasy Translate | Forward translation check | DNA sequence | Six-frame protein | Free | Read the correct frame; it shows all six |
| GenScript Rare Codon Analysis | CAI and GC readout in a browser | DNA sequence | CAI, GC, rare codon report | Free tool, commercial vendor | A vendor tool tied to their synthesis service; fine as a cross-check, not as your documented method |
| JCat | Codon adaptation for a chosen host | Protein or DNA | Adapted DNA and CAI | Free | Server unavailable. See below. |
A note on JCat, since it is the tool most published immunoinformatics papers cite for this step and the one your supervisor will name. Checked on 1 September 2026: the original host fails to establish a working HTTPS connection, and the PRODORIC-hosted page loads but its entire body reads that the server is under maintenance and will return in a few days. So it returns a healthy status code while being unusable. That is why the workflow above is built on tools that are live. Check it again yourself before writing it into your methods.
Troubleshooting: real errors and their fixes
- The output is full of CCC and AGA codons. You left the EBI codon table on
Ehuman.cut. Resubmit withEecoli.cut. - The E. coli K12 frequencies do not match the published values. You are on Kazusa
species=83333, which holds 14 CDS. Switch to W3110,species=316407. - CAI came out at or near 1.0. You computed CAI against the same table you optimized with, which is circular. Recompute against an independent reference set of highly expressed genes and name it.
- GC3 is above 90%. You used top-codon-only optimization. Sample codons in proportion to their frequency, with a floor that excludes the rarest ones.
- The synthesis vendor flagged the sequence, or the vector will not cut. An internal restriction site appeared. Re-run NEBcutter, find the offending codon pair, and silently recode one of the two.
- The optimized DNA no longer translates to your construct. A base was added or lost, usually by pasting a sequence with a line-wrapping artefact. Run Expasy Translate and compare character by character.
- JCat will not load. The server is down as of 1 September 2026, not a problem at your end. Use the workflow above.
Frequently asked questions
Does codon optimization change the protein?
No. Every substitution is synonymous, so the amino acid sequence is identical. That is precisely why you must verify by translating the final DNA back and comparing it to the original construct. If the protein changed, you made an error, not an optimization.
Do I need to codon optimize at all for an MSc project?
If your project is purely computational and ends at the MD simulation, no. Include it when your write-up claims the construct is expressible, because a reviewer will ask how you know. It is also a short, self-contained section that demonstrates you understand the gap between an in-silico design and a wet-lab reagent.
What CAI value should I aim for?
There is no universal threshold, and any specific number quoted without a reference set is not meaningful. Sharp and Li describe CAI as an approximate indication of likely expression success, not a pass mark. Report the value, name the reference set, and discuss it alongside GC3 and rare-codon counts rather than in isolation.
Can I just use a commercial vendor’s optimization tool?
You can, as a cross-check. The problem for a dissertation is reproducibility: vendor algorithms are proprietary, so a reviewer cannot repeat your result. Document a method built on the open tools above, then use the vendor tool to confirm your numbers agree.
Which E. coli strain table should I choose?
Match the strain you will transform. W3110 is a K-12 lab strain and is the sensible default for standard expression work. Say which entry you used and how many CDS it contains, because as the table above shows, two entries both labelled E. coli can disagree by more than threefold on a codon’s frequency.
Where this fits in the wider skill set
Codon optimization is one small step in a much longer chain, and it only makes sense once the epitope screening, construct assembly, docking and simulation stages are behind you. The full sequence of skills is mapped in our immunoinformatics pillar guide, and the wider programme, including the Python and structural biology that makes the Biopython route above practical, is laid out in the computational biology skills roadmap.
Written by the StemSkills Lab team, who bring 10+ years in sequence and structural bioinformatics, drug discovery and design, and multiscale molecular modeling.
Want the guided, hands-on version?
Our live Molecular Modeling & MD Simulations cohort bootcamp takes you from zero to running real docking and MD workflows, with a portfolio project for your grad-school applications.
