MODELLER Tutorial: Build a Homology Model Step by Step

MODELLER builds a homology model in five scripted steps: search a PDB sequence database for templates, compare the hits and pick one, align target to template with align2d(), build models with the AutoModel class, then rank them by DOPE score. Install it with conda from the salilab channel using a free academic licence key.
Most students meet homology modelling through a web server, submit a sequence, and get a structure back without ever seeing the alignment that produced it. That is fine until the day your target has 28% identity to its best template, or the domain you care about is covered by two different structures, or a reviewer asks you to hand over the exact alignment you modelled from. At that point you need the alignment in your own hands. This walkthrough, written by the StemSkills Lab team from 10+ years in sequence and structural bioinformatics, drug discovery and design, and multiscale molecular modeling, takes you through MODELLER on the command line using the official tutorial data, so every command below is one you can run today. If you have not built a model before at all, start with our SWISS-MODEL homology modelling tutorial and come back here. For the order to learn these skills in, see the computational biology skills roadmap.
What is MODELLER and how does it actually build a structure?
MODELLER does not copy the template backbone and paste your sequence onto it. It converts the alignment into a set of spatial restraints, distances, angles and dihedrals that your model should satisfy because homologous proteins satisfy them, then finds coordinates that violate those restraints as little as possible. The method comes from Šali and Blundell, Comparative Protein Modelling by Satisfaction of Spatial Restraints (Journal of Molecular Biology, 1993, 234, 779 to 815), a paper Crossref records as cited over 11,000 times, which is why MODELLER output still appears in methods sections three decades later.
The practical consequence is the one thing every beginner needs to hear: the alignment is the model. The optimiser is good at satisfying restraints and has no opinion about whether your restraints were the right ones. A single-residue shift in a loop alignment produces a model that scores fine and is wrong. Everything in this tutorial exists to get the alignment right before you build anything.
When should you use MODELLER instead of SWISS-MODEL?
Use the web server when the job is routine and the identity is comfortable. Use MODELLER when you need control over a specific decision the server makes for you, or when the work has to be reproducible from a script.
| Decision | SWISS-MODEL | MODELLER |
|---|---|---|
| Setup | Web browser, no install | Local install plus a licence key |
| Licence | Free, open web server | Free for academic non-profit use, 5-year term, registration required |
| Template choice | Automated search and ranking | You search, inspect and choose |
| Alignment | Built for you, limited editing | Fully yours, hand-editable PIR file |
| Multiple templates | Limited | Native, list several codes in knowns |
| Models returned | One per template | As many as you ask for, ranked |
| Reproducible in a script | No | Yes, the script is the record |
| Best for | A quick model at high identity | Low identity, custom alignments, chimeras, loop rebuilding, thesis work |
They are not rivals in practice. A common workflow is to run SWISS-MODEL first for a sanity check, then rebuild in MODELLER once you know which template you want and which loops need attention. If you are weighing both against a predicted structure, our comparison of AlphaFold, homology modelling and experimental structures covers when each one is the honest answer.
How do you install MODELLER and get the academic licence key?
MODELLER is free for academic non-profit institutions. Commercial and government labs need a separate licence handled by BIOVIA. Register with your institutional email address at the MODELLER registration page, because the licence server tries to verify academic status automatically and a personal address will slow you down. The key arrives by email.
The current release is version 10.8, dated 6 November 2025. The conda route is the least painful on any platform:
conda config --add channels salilab
conda install modellerThe installer then prompts you to paste the key into a file. You can skip the prompt by exporting the key first:
export KEY_MODELLER=YOUR_KEY_HERE
conda install modellerIf you ever need to change the key later, it lives in modlib/modeller/config.py inside your MODELLER installation, and that file takes precedence over the environment variable. Confirm the install with:
python -c "from modeller import *; env = Environ(); print('ok')"If that prints ok, you are ready. Now download the official basic tutorial example and unpack it. Every script below is from that package, so you can run each one and compare your output to theirs.
How do you search for a template with build_profile.py?
The tutorial target is TvLDH, a lactate dehydrogenase sequence from Trichomonas vaginalis. Your target sequence goes into a PIR-format file, TvLDH.ali, which looks like this:
>P1;TvLDH
sequence:TvLDH:::::::0.00: 0.00
MSEAAHVLITGAAGQIGYILSHWIASGELYGDRQVYLHLLDIPPAMNRLTALTMELEDCAFPHLAGFVATTDPKA
...
EGFKVNDWLREKLDFTEKDLFHEKEIALNHLAQGG*Three details break more first attempts than anything else. The header line must start with >P1; and the code after it must match what you later pass to sequence=. The second line has exactly ten colon-separated fields. The sequence must end with an asterisk.
Then search a non-redundant PDB sequence database for relatives. The tutorial’s build_profile.py reads pdb_95.pir, converts your sequence to a profile and scans:
from modeller import *
log.verbose()
env = Environ()
sdb = SequenceDB(env)
sdb.read(seq_database_file='pdb_95.pir', seq_database_format='PIR',
chains_list='ALL', minmax_db_seq_len=(30, 4000), clean_sequences=True)
sdb.write(seq_database_file='pdb_95.bin', seq_database_format='BINARY',
chains_list='ALL')
sdb.read(seq_database_file='pdb_95.bin', seq_database_format='BINARY',
chains_list='ALL')
aln = Alignment(env)
aln.append(file='TvLDH.ali', alignment_format='PIR', align_codes='ALL')
prf = aln.to_profile()
prf.build(sdb, matrix_offset=-450, rr_file='${LIB}/blosum62.sim.mat',
gap_penalties_1d=(-500, -50), n_prof_iterations=1,
check_profile=False, max_aln_evalue=0.01)
prf.write(file='build_profile.prf', profile_format='TEXT')
aln = prf.to_alignment()
aln.write(file='build_profile.ali', alignment_format='PIR')Run it with python build_profile.py. Read build_profile.prf, not the log. The columns that matter are the percentage sequence identity to your target and the alignment e-value.
How do you choose between several candidate templates?
Sequence identity alone is a weak tiebreaker once several hits are in the same range. The tutorial’s compare.py loads the six candidate chains and compares them structurally as well as by sequence:
from modeller import *
env = Environ()
aln = Alignment(env)
for (pdb, chain) in (('1b8p', 'A'), ('1bdm', 'A'), ('1civ', 'A'),
('5mdh', 'A'), ('7mdh', 'A'), ('1smk', 'A')):
m = Model(env, file=pdb, model_segment=('FIRST:'+chain, 'LAST:'+chain))
aln.append_model(m, atom_files=pdb, align_codes=pdb+chain)
aln.malign()
aln.malign3d()
aln.compare_structures()
aln.id_table(matrix_file='family.mat')
env.dendrogram(matrix_file='family.mat', cluster_cut=-1.0)The dendrogram shows which candidates are structurally interchangeable, so you are choosing between families rather than between six nearly identical options. The tutorial settles on chain A of 1BDM, a malate dehydrogenase, for two stated reasons: a better crystallographic R-factor of 16.9% and a higher sequence identity to the query of 45%.
Use the same two criteria on your own project, in this order of priority:
- Sequence identity to your target. Above 50% you can expect a model close to a medium-resolution experimental structure. Between 30% and 50% the fold is usually right and the loops and side chains are not. Below 30% you are in the twilight zone where alignment errors dominate and a single template may not be defensible.
- Structure quality. Prefer better resolution and a lower R-factor, and prefer a template that is complete over one with disordered gaps. If the best-identity template has a hole in the region you care about, that is a real cost. Our guide to fixing missing residues and loops in a PDB structure covers what to do about it.
Also check that the template was solved in a biologically relevant state. A structure with your ligand class bound is worth more than a slightly higher-identity apo structure if the model is heading for docking.
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.
How do you align the target to the template with align2d?
This is the step that separates MODELLER from a generic sequence aligner. The align2d() command uses structural information from the template while it builds the alignment, so it knows to avoid opening gaps inside helices and strands and to place them in loops and on the surface instead. A gap put through the middle of a beta strand is a modelling error that no amount of optimisation will recover from.
from modeller import *
env = Environ()
aln = Alignment(env)
mdl = Model(env, file='1bdm', model_segment=('FIRST:A','LAST:A'))
aln.append_model(mdl, align_codes='1bdmA', atom_files='1bdm.pdb')
aln.append(file='TvLDH.ali', align_codes='TvLDH')
aln.align2d(max_gap_length=50)
aln.write(file='TvLDH-1bdmA.ali', alignment_format='PIR')
aln.write(file='TvLDH-1bdmA.pap', alignment_format='PAP')Two files come out on purpose. The PIR file is what the modelling step reads. The PAP file is for your eyes, with a conservation row underneath so you can scan it:
_aln.pos 10 20 30 40 50 60
1bdmA MKAPVRVAVTGAAGQIGYSLLFRIAAGEMLGKDQPVILQLLEIPQAMKALEGVVMELEDCAFPLLAGL
TvLDH MSEAAHVLITGAAGQIGYILSHWIASGELYG-DRQVYLHLLDIPPAMNRLTALTMELEDCAFPHLAGF
_consrvd * * ********* * ** ** * * * * ** ** ** * ********* ***Open the PAP file and read it before you build anything. You are looking for gaps that fall inside secondary structure, long insertions in your target with nothing to model them from, and the termini, where models are routinely worst. If you see something wrong, edit the PIR file by hand and rerun. Hand-editing the alignment is not a hack, it is the reason you chose MODELLER.
How do you build the models with AutoModel?
The build script is short because the AutoModel class carries the default protocol:
from modeller import *
from modeller.automodel import *
env = Environ()
a = AutoModel(env, alnfile='TvLDH-1bdmA.ali',
knowns='1bdmA', sequence='TvLDH',
assess_methods=(assess.DOPE,
assess.GA341))
a.starting_model = 1
a.ending_model = 5
a.make()Read it argument by argument, because these are the four things you change on your own project. alnfile is the PIR alignment. knowns is the template code exactly as it appears in that alignment, and it takes a tuple when you have several templates. sequence is your target code. starting_model and ending_model set how many models to build, each from a different random starting point.
Build five to start with. Building one tells you nothing about whether the optimiser converged; building five and seeing them agree is evidence. If your target has long insertions relative to the template, raise this to 20 or more, because those regions are where the models will differ and you want to sample them.
The tutorial run took 316 seconds of CPU time for five models of a 336-residue alignment, which is a useful expectation to carry: minutes, not hours, on a laptop.
How do you choose the final model by DOPE score?
At the end of the run MODELLER prints a summary table. Here is the real output from the tutorial run:
>> Summary of successfully produced models:
Filename molpdf DOPE score GA341 score
----------------------------------------------------------------------
TvLDH.B99990001.pdb 1763.56104 -38079.76172 1.00000
TvLDH.B99990002.pdb 1560.93396 -38515.98047 1.00000
TvLDH.B99990003.pdb 1712.44104 -37984.30859 1.00000
TvLDH.B99990004.pdb 1720.70801 -37869.91406 1.00000
TvLDH.B99990005.pdb 1840.91772 -38052.00781 1.00000Three numbers, three different jobs:
| Score | What it measures | How to read it | Use it to |
|---|---|---|---|
| molpdf | The value of MODELLER’s own objective function, restraint violation | Lower is better, arbitrary units | Check the optimiser converged, not to rank quality |
| DOPE score | A statistical potential trained on native structures | More negative is better, scales with size | Rank models of the same target against each other |
| GA341 | Probability the fold is correct | 0 to 1, above 0.7 is the usual pass mark | Ask whether the fold is right at all, not which model is best |
In this run, GA341 is 1.00000 for all five, which is what you expect at 45% identity and is why it is useless as a tiebreaker here. molpdf and DOPE also disagree slightly in their ordering, which is normal. Rank by DOPE. The winner is TvLDH.B99990002.pdb at -38515.98, the most negative of the five, and it is also the model the tutorial carries forward.
The reason to trust DOPE over molpdf for this decision is in Shen and Sali, Statistical potential for assessment and prediction of protein structures (Protein Science, 2006, 15, 2507 to 2524). Benchmarked against decoy sets, the authors report that “for all decoy sets, DOPE is the best performing function in terms of all criteria, except for a tie in one criterion for one decoy set”, and that DOPE correctly identified the native structure for 28 of 32 targets across five multiple-target decoy sets, against 27 for DFIRE and 14 for Rosetta.
One caveat that catches people out in their thesis defence: the DOPE score is not normalised by protein size, so -38515 means nothing on its own and cannot be compared with the DOPE score of a different protein. It only ranks models of the same target.
How do you check the chosen model is actually good?
Picking the best of five is not the same as the best of five being good. Run a per-residue DOPE profile and compare it against the template:
from modeller import *
from modeller.scripts import complete_pdb
log.verbose()
env = Environ()
env.libs.topology.read(file='$(LIB)/top_heav.lib')
env.libs.parameters.read(file='$(LIB)/par.lib')
mdl = complete_pdb(env, 'TvLDH.B99990002.pdb')
s = Selection(mdl)
s.assess_dope(output='ENERGY_PROFILE NO_REPORT', file='TvLDH.profile',
normalize_profile=True, smoothing_window=15)Run the same script on the template, pointing complete_pdb at 1bdm.pdb with model_segment=('FIRST:A', 'LAST:A'), then plot the two profiles together. The tutorial ships plot_profiles.py for exactly this. What you are looking for is regions where the model’s per-residue score is markedly worse than the template’s. Those peaks are your problem loops, usually insertions with no structural information behind them, and they are the honest limitation to report in your methods section.
Then take the model out of MODELLER entirely and validate it the way an experimental structure would be validated, with a Ramachandran plot and a MolProbity run. Our guide on validating a protein structure walks through reading those outputs. A model that scores well on DOPE and has 4% Ramachandran outliers is still a model you need to fix.
What are the most common MODELLER errors and how do you fix them?
These are the failures that stop beginners, with what each one actually means.
“Alignment sequence not found in PDB file” or “Number of residues in the alignment and pdb files are different.” MODELLER reads the template sequence from the ATOM and HETATM records of the PDB file, not from SEQRES. If your alignment contains residues that were never resolved in the crystal, the two sequences do not match and it stops. The MODELLER FAQ gives a short script to dump exactly what MODELLER sees:
from modeller import *
env = Environ()
code = '1BY8'
mdl = Model(env, file=code)
aln = Alignment(env)
aln.append_model(mdl, align_codes=code)
aln.write(file=code+'.seq')Diff that sequence against your alignment and the mismatch will be obvious. Also check the chain and residue range in your alignment header.
The licence key is rejected. The key is version-specific and must be typed exactly as it arrived by email. Check modlib/modeller/config.py in your installation, because the value set there overrides the KEY_MODELLER environment variable.
The PDB file cannot be found. MODELLER looks in the current directory by default. Either keep the template PDB beside your script or set env.io.atom_files_directory = './:../atom_files'.
Your ligand, metal or waters vanished from the model. HETATM records are ignored unless you ask for them. Set env.io.hetatm = True and, for waters, env.io.water = True, and include the corresponding residues in the alignment as a block of dots.
Warnings such as “Could not find platform independent libraries” or “import site failed”. These refer to missing Python modules and, per the official FAQ, can usually be ignored, because most MODELLER scripts do not need them. Parallel task support is the exception and will genuinely fail without the socket module.
The model has knots or badly tangled loops. Almost always an alignment problem rather than an optimisation problem. Go back to the PAP file, look at the region that is tangled, and check whether a gap landed inside secondary structure.
Frequently asked questions
Is MODELLER free?
It is free for academic non-profit institutions under a 5-year licence, obtained by registering with an institutional email address. Commercial and government users, including national laboratories, need a separate licence handled by BIOVIA.
How many models should I build?
Five is enough when identity is high and the alignment has no long insertions. Raise it to 20 or more when the target has insertions relative to the template, because those are the regions that will vary between runs and you want to sample them properly before picking one.
Can MODELLER use more than one template?
Yes, and it is one of the main reasons to use it over a web server. Put every template in the alignment file and pass their codes as a tuple to knowns, for example knowns=('1bdmA', '5mdhA'). This is also how you model a multi-domain protein from separate single-domain structures, though you should orient the templates sensibly first if the domains do not overlap.
What sequence identity do I need for a usable model?
Above 50%, expect accuracy comparable to a medium-resolution experimental structure. Between 30% and 50%, expect a correct fold with unreliable loops and side chains. Below 30%, alignment errors dominate and you should treat a single-template model as a hypothesis, not a structure.
Should I use MODELLER or AlphaFold in 2026?
They answer different questions. AlphaFold gives you one predicted structure with per-residue confidence and no template to point at. MODELLER gives you a model whose provenance is a specific template and a specific alignment you can show a reviewer, and it lets you build a chimera, model a specific conformational state by choosing the template, or rebuild missing loops in an existing structure. Many projects use both and compare them.
How do I cite MODELLER?
Cite Šali and Blundell (1993) in Journal of Molecular Biology for the method, and add Webb and Sali, Comparative Protein Structure Modeling Using Modeller, Current Protocols in Bioinformatics 54, 5.6.1 to 5.6.37, 2016, for the current program. State the version, the template PDB code and chain, the number of models built, and which score you ranked by.
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.
