Meeko Tutorial: Prepare Ligands and Receptors for Vina

Meeko is the Python package the AutoDock Vina documentation now uses to prepare docking inputs. Run mk_prepare_ligand.py -i ligand.sdf -o ligand.pdbqt on a ligand that already has explicit hydrogens and 3D coordinates. Then run mk_prepare_receptor.py with -p to write the receptor PDBQT and -v with --box_size and --box_center to write the Vina box. After docking, mk_export.py converts the poses back to SDF.
This guide is from the StemSkills Lab team, who have spent more than ten years on structural bioinformatics, drug design and molecular modeling. We ran every command below on Meeko 0.8.0 (installed with pip on Python 3.12, with RDKit 2026.9.1) against PDB entry 1IEP, the Abl kinase domain bound to imatinib. That is the same system the official Vina basic docking tutorial uses, so you can compare your output with ours. Docking itself is covered in our molecular docking learning hub. This post covers the step most students get wrong: input preparation.
What is Meeko and why does AutoDock Vina recommend it?
Meeko prepares inputs for AutoDock and reads its outputs. The project README describes it this way: “Meeko prepares the input for AutoDock and processes its output.” It is developed by the Forli lab alongside AutoDock-GPU and AutoDock Vina, and it handles both small molecules and receptors (proteins and nucleic acids).
The AutoDock Vina basic docking tutorial uses Meeko for receptor and ligand preparation. The practical reason is round-tripping. Meeko writes a SMILES string into the header of every ligand PDBQT. When you convert docked poses back to SDF, Meeko uses that SMILES to rebuild the correct bond orders. A PDBQT file stores atoms, charges and atom types but no bond orders, so tools that read PDBQT without that header have to guess the chemistry, and for some molecules the guess fails.
The other reason is that the older route, AutoDockTools from MGLTools, runs on Python 2, which reached end of life in 2020. Meeko runs on current Python and builds on RDKit, so it fits into the same scripts you use for cheminformatics.
How do I install Meeko?
The README gives two options. Use one of them inside a fresh environment.
pip install meeko
# or, with conda-forge:
micromamba install -c conda-forge meekoThe pip route pulls in RDKit, NumPy, SciPy and gemmi, and adds three command-line scripts: mk_prepare_ligand.py, mk_prepare_receptor.py and mk_export.py. Check them with:
mk_prepare_ligand.py --help
mk_prepare_receptor.py --helpOne version note from our own setup: on a machine whose default Python was 3.14, creating the virtual environment failed at the pip bootstrap step, while Python 3.12 worked without trouble. If python -m venv errors out, try an older interpreter before debugging Meeko.
The -i option of mk_prepare_receptor.py reads PDB or mmCIF through ProDy, which is a separate install (pip install prody). If you only have PDB files, --read_pdb works without ProDy. We used --read_pdb for every receptor run in this guide.
How do I prepare a ligand with mk_prepare_ligand?
Meeko does not invent geometry or hydrogens for a ligand. It expects an input molecule that already has explicit hydrogens and 3D coordinates, as one connected fragment. The cleanest way to get there is RDKit. This script builds imatinib from SMILES and writes an SDF:
from rdkit import Chem
from rdkit.Chem import AllChem
smi = "Cc1ccc(NC(=O)c2ccc(CN3CCN(C)CC3)cc2)cc1Nc1nccc(-c2cccnc2)n1"
mol = Chem.AddHs(Chem.MolFromSmiles(smi)) # explicit hydrogens
AllChem.EmbedMolecule(mol, randomSeed=42) # 3D coordinates
AllChem.MMFFOptimizeMolecule(mol) # quick clean-up
mol.SetProp("_Name", "imatinib")
w = Chem.SDWriter("imatinib.sdf"); w.write(mol); w.close()Then convert it:
mk_prepare_ligand.py -i imatinib.sdf -o imatinib.pdbqtOn our run this wrote 39 atoms: the 37 heavy atoms of imatinib plus its 2 polar NH hydrogens. Non-polar hydrogens are merged into their carbons, which is the default (--merge_these_atom_types defaults to H). The file ends with TORSDOF 7, meaning Meeko found seven rotatable bonds for Vina to explore. Partial charges are Gasteiger by default (--charge_model gasteiger).
Look at the top of the file and you will see the REMARK SMILES line plus a REMARK SMILES IDX map. Do not delete them; mk_export.py needs them later.
Protonation is your job, not Meeko’s. The SMILES above is neutral imatinib. At physiological pH the N-methyl piperazine is likely protonated, and the Vina docs remind users to always check protonation before docking. Decide the state you want (with a tool such as Dimorphite-DL, Open Babel -p 7.4, or your own judgment from pKa values), write that form to SDF, and only then run Meeko.
How do I prepare many ligands at once?
Give Meeko a multi-molecule SDF and an output folder instead of -o:
mk_prepare_ligand.py -i library.sdf --multimol_outdir pdbqt_libraryEach molecule is written as <name>.pdbqt, using the SDF title line. Add -z to pack the output into .tar.gz files, or --name_from_prop to take names from an SDF property such as a compound ID.
How do I prepare the receptor with mk_prepare_receptor?
Start from a clean protein file. For 1IEP we kept chain A and its ATOM records only, dropping waters, chloride ions and the bound imatinib:
curl -s -o 1iep.pdb https://files.rcsb.org/download/1IEP.pdb
grep '^ATOM' 1iep.pdb | awk 'substr($0,22,1)=="A"' > recA.pdbThen run the same options the Vina tutorial uses:
mk_prepare_receptor.py --read_pdb recA.pdb -o 1iep_receptor -p -v \
--box_size 20 20 20 --box_center 15.190 53.903 16.917What each option does:
-o 1iep_receptorsets the base name for every output file.-pwrites1iep_receptor.pdbqt, the rigid receptor.-vwrites1iep_receptor.box.txt, a Vina config file withcenter_xtosize_z, plus1iep_receptor.box.pdbso you can see the box in PyMOL or ChimeraX.--box_sizeand--box_centerare in angstroms.
Meeko matches every residue against chemical templates, so it adds the hydrogens the templates call for. Our heavy-atom-only chain A came out with 470 polar hydrogens (atom type HD) and template-derived Gasteiger charges. The official tutorial adds hydrogens with reduce2 first, which gives you more control over histidine tautomers and flipped Asn and Gln side chains. If those matter for your pocket, protonate first and set specific states with -n (for example -n A:5,7=CYX,B:17=HID, the format from the help text).
How do I center the box on the co-crystallized ligand?
Typing coordinates by hand is a common source of a box in the wrong place. Meeko can build the box around a reference molecule instead:
grep '^HETATM' 1iep.pdb | awk 'substr($0,22,1)=="A" && substr($0,18,3)=="STI"' > sti_A.pdb
mk_prepare_receptor.py --read_pdb recA.pdb -o 1iep_env -p -v \
--box_enveloping sti_A.pdb --padding 5Our run produced a center of 15.190, 53.903, 16.917, exactly the center the Vina tutorial uses, and a box of 18.7 x 26.7 x 23.5 angstroms that follows the shape of imatinib with 5 angstroms of padding. That match is a useful sanity check: the tutorial’s box is centered on the crystal ligand.
How do I make side chains flexible?
Pass residues with -f as chain:number. For the gatekeeper Thr315 of Abl:
mk_prepare_receptor.py --read_pdb recA.pdb -o 1iep_flex -p -v -j \
-f A:315 --box_enveloping sti_A.pdb --padding 5With flexible residues, -p writes two files, 1iep_flex_rigid.pdbqt and 1iep_flex_flex.pdbqt, which you pass to Vina with --receptor and --flex. The -j option writes a JSON description of the prepared receptor that mk_export.py can read later to rebuild the full complex.
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 I run Vina and convert the poses back to SDF?
With both files prepared, the docking command from the Vina documentation is:
vina --receptor 1iep_receptor.pdbqt --ligand 1iep_ligand.pdbqt \
--config 1iep_receptor.box.txt \
--exhaustiveness=32 --out 1iep_ligand_vina_out.pdbqtThen turn the poses into SDF, which every viewer and cheminformatics tool reads correctly:
mk_export.py 1iep_ligand_vina_out.pdbqt -s 1iep_ligand_vina_out.sdfIf you prepared the receptor with -j, add -j 1iep_receptor.json -p complex.pdb to also write the receptor (including moved flexible side chains) as PDB. Because mk_export.py rebuilds bonds from the SMILES remark, the SDF keeps correct aromaticity and bond orders, and the merged hydrogens are added back to the pose.
What does Meeko do with macrocycles?
Rings are normally rigid in docking, which is a problem for macrocycles whose conformation matters. By default Meeko opens rings of 7 or more atoms (--min_ring_size, default 7). It breaks one ring bond and marks the two broken ends with pseudo-atoms, typed G0 and CG0 in the PDBQT. Vina’s scoring then pulls those ends back together, so the ring can flex during the search and still close.
We tested this on a 13-membered lactam (laurolactam). The default run wrote 2 G0 and 2 CG0 atoms. With --rigid_macrocycles, the ring was kept closed in its input conformation and no G atoms appeared. Use the rigid option when you trust a crystal or pre-computed conformer, and the default when you want the docking search to sample ring shapes.
How does Meeko compare with AutoDockTools and Open Babel?
| Feature | Meeko | AutoDockTools / ADFR scripts | Open Babel |
|---|---|---|---|
| Runtime | Current Python 3, built on RDKit | MGLTools runs on Python 2; the ADFR suite bundles its own Python | C++ program with the command-line tool obabel |
| Ligand PDBQT | mk_prepare_ligand.py | prepare_ligand4.py or ADFR prepare_ligand | obabel lig.sdf -O lig.pdbqt |
| Receptor PDBQT | mk_prepare_receptor.py (residue templates) | ADFR prepare_receptor | Possible, but no residue templates |
| Bond orders after docking | Rebuilt from the SMILES remark | Not stored | Guessed from coordinates |
| Writes the Vina box | Yes, -v and --box_enveloping | No, set by hand or in the GUI | No |
| Macrocycle flexibility | Yes, G0/CG0 ring opening | No | No |
| Used in the Vina docs tutorial | Yes, receptor and ligand | ADFR prepare_receptor shown as an alternative | No |
How do I fix common Meeko errors?
These are messages we triggered on purpose with Meeko 0.8.0, so you can match them exactly.
“RDKit molecule has implicit Hs. Need explicit Hs.”
Cause: the SDF has no hydrogen atoms. Many downloaded files and most 2D drawings do not. Fix: load the file in RDKit, call Chem.AddHs(mol, addCoords=True) (or re-embed with AllChem.EmbedMolecule), and write it again. Meeko reports PDBQT files written: 0 for this molecule.
“RDKit molecule has 2 fragments. Must have 1.”
Cause: a salt or a mixture, for example a hydrochloride where the chloride is stored in the same record. Fix: keep the largest fragment before preparing. In RDKit, rdMolStandardize.LargestFragmentChooser().choose(mol) (import rdMolStandardize from rdkit.Chem.MolStandardize) does it; then re-check protonation.
Ligand runs without error but every z coordinate is 0.000
Cause: the SDF was a 2D drawing with hydrogens added but no 3D embedding. Meeko accepted it silently in our test and wrote a flat ligand, which Vina will dock poorly. Fix: embed in 3D first. A quick check is awk '$1=="ATOM"{print $8}' lig.pdbqt | sort -u; a single value of 0.000 means the input was flat.
“Template matching failed for: [‘A:300’]”
Cause: a residue with missing atoms. We reproduced it by deleting the side chain of Gln300; disordered side chains in crystal structures cause the same thing. Fix: rebuild missing side chains (for example with PDBFixer or Modeller), or remove the residue with -x (--delete_bad_res). If the residue is far from the pocket, --delete_bad_res_from_box_radius removes it only when it lies outside the box. Note that the 0.8.0 error text suggests -a/--allow_bad_res, which does not appear in that version’s help; the working flag is -x.
The co-crystal ligand ended up inside the receptor PDBQT
Cause: you kept HETATM records. Meeko does not refuse them; it warns “Trying to resolve unknown residues by building chemical templates” and writes them into the receptor. In our test, imatinib and 4 chloride ions were written into the receptor file, so the pocket would already be occupied. Fix: strip ligands, unwanted ions and waters before preparation. Keep a metal only when it is part of the binding site, and check how it was typed.
Which sources should I cite for this workflow?
- Eberhardt J, Santos-Martins D, Tillack AF, Forli S. AutoDock Vina 1.2.0: New Docking Methods, Expanded Force Field, and Python Bindings. J Chem Inf Model. 2021;61(8):3891-3898.
- Trott O, Olson AJ. AutoDock Vina: improving the speed and accuracy of docking with a new scoring function, efficient optimization, and multithreading. J Comput Chem. 2010;31(2):455-461. The paper reports approximately two orders of magnitude speed-up over AutoDock 4.
- The Meeko paper, “Meeko: molecule parameterization and software interoperability for docking and beyond”, linked from the Meeko GitHub README (DOI 10.1021/acs.jcim.5c02271), and the Meeko documentation.
If you are deciding where Meeko fits in a full learning plan (structure retrieval, preparation, docking, then MD), our computational biology skills roadmap lays out the order, and the molecular docking hub collects the related guides.
Frequently asked questions
Does Meeko add hydrogens to my ligand?
No. mk_prepare_ligand.py stops with “RDKit molecule has implicit Hs. Need explicit Hs.” Add hydrogens and 3D coordinates in RDKit or another tool first, after deciding the protonation state you want.
Can I still use AutoDockTools PDBQT files with Vina?
Yes, Vina reads any valid PDBQT. The advantage of Meeko is that its ligand files carry a SMILES remark, so mk_export.py can convert docked poses back to SDF with correct bond orders.
What box size should I use with mk_prepare_receptor?
The Vina tutorial uses 20 x 20 x 20 angstroms for imatinib in 1IEP. For a known pocket, --box_enveloping ligand.pdb --padding 5 sizes the box around a reference ligand, which avoids hand-typed coordinate errors.
Do I need ProDy to run mk_prepare_receptor?
Only for -i, which reads PDB and mmCIF through ProDy. The --read_pdb option reads PDB files without it.
Which charge model does Meeko use?
Gasteiger by default for ligands. --charge_model also accepts espaloma, nagl, zero and read, where read takes charges already stored in the input file.
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.
