[{"data":1,"prerenderedAt":1041},["ShallowReactive",2],{"doc:\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Finstall-python-packages-into-qgis":3},{"id":4,"title":5,"body":6,"description":1030,"extension":1031,"meta":1032,"navigation":244,"path":1037,"seo":1038,"stem":1039,"__hash__":1040},"docs\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Finstall-python-packages-into-qgis\u002Findex.md","Install Python Packages into the QGIS Environment",{"type":7,"value":8,"toc":1017},"minimark",[9,13,39,48,184,189,206,210,305,327,331,385,397,400,438,452,456,469,478,495,595,599,602,625,634,671,685,755,759,762,768,779,784,788,853,856,860,910,914,934,938,944,950,956,962,968,982,986,1013],[10,11,5],"h1",{"id":12},"install-python-packages-into-the-qgis-environment",[14,15,16,17,21,22,25,26,29,30,34,35,38],"p",{},"Sooner or later a PyQGIS script needs something QGIS does not ship — ",[18,19,20],"code",{},"requests"," for an API, ",[18,23,24],{},"pandas"," for a summary table, ",[18,27,28],{},"openpyxl"," because somebody wants the output in a spreadsheet. The install itself is one command; getting it into the ",[31,32,33],"em",{},"right"," Python is the part that goes wrong, because a machine running QGIS usually has three or four interpreters and ",[18,36,37],{},"pip install"," in a terminal reaches the wrong one.",[14,40,41,42,47],{},"This recipe belongs to ",[43,44,46],"a",{"href":45},"\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002F","Virtual Environments for GIS",". It covers finding the interpreter QGIS is using, installing into it safely on each platform, keeping installs out of the way of QGIS upgrades, and the packages you must not touch.",[14,49,50],{},[51,52,57,61,65,72,89,98,108,114,119,123,127,130,133,136,139,141,147,151,154,157,160,168,173,177],"svg",{"viewBox":53,"role":54,"ariaLabel":55,"xmlns":56},"0 0 760 284","img","Diagram of the interpreters typically present on a machine running QGIS, showing the system Python, a project virtual environment and the QGIS Python, with only the last one visible to PyQGIS scripts","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[58,59,60],"title",{},"Three Pythons, one of which matters",[62,63,64],"desc",{},"A typical machine has a system Python used by the operating system, one or more project virtual environments, and the Python that QGIS itself runs. A package installed into the first two is invisible to PyQGIS. Only packages installed into the QGIS interpreter, or into a location on its path, can be imported from the QGIS console.",[66,67],"rect",{"x":68,"y":68,"width":69,"height":70,"fill":71},"0","760","284","#f6f3ea",[73,74,75],"defs",{},[76,77,84],"marker",{"id":78,"viewBox":79,"refX":80,"refY":81,"markerWidth":82,"markerHeight":82,"orient":83},"pyEnvArrow","0 0 10 10","8","5","7","auto-start-reverse",[85,86],"path",{"d":87,"fill":88},"M0 0 L10 5 L0 10 z","#2f3b35",[90,91,97],"text",{"x":92,"y":93,"style":94,"fill":95,"textAnchor":96},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","pip in a terminal almost never means the QGIS Python",[66,99],{"x":100,"y":101,"width":102,"height":103,"rx":104,"fill":105,"stroke":106,"style":107},"16","52","232","128","10","#fdf2e2","#b45309","stroke-width:2",[90,109,113],{"x":110,"y":111,"style":112,"fill":106,"textAnchor":96},"132","78","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","system Python",[90,115,118],{"x":110,"y":116,"style":117,"fill":88,"textAnchor":96},"104","text-anchor:middle;font-size:11px;font-family:sans-serif","what a bare pip finds",[90,120,122],{"x":110,"y":121,"style":117,"fill":88,"textAnchor":96},"126","used by the OS",[90,124,126],{"x":110,"y":125,"style":112,"fill":106,"textAnchor":96},"152","invisible to QGIS",[66,128],{"x":129,"y":101,"width":102,"height":103,"rx":104,"fill":105,"stroke":106,"style":107},"264",[90,131,132],{"x":92,"y":111,"style":112,"fill":106,"textAnchor":96},"a project virtualenv",[90,134,135],{"x":92,"y":116,"style":117,"fill":88,"textAnchor":96},"your analysis code",[90,137,138],{"x":92,"y":121,"style":117,"fill":88,"textAnchor":96},"activated in a shell",[90,140,126],{"x":92,"y":125,"style":112,"fill":106,"textAnchor":96},[66,142],{"x":143,"y":101,"width":102,"height":103,"rx":104,"fill":144,"stroke":145,"style":146},"512","#eef7f4","#0f766e","stroke-width:2.5",[90,148,150],{"x":149,"y":111,"style":112,"fill":145,"textAnchor":96},"628","the QGIS Python",[90,152,153],{"x":149,"y":116,"style":117,"fill":88,"textAnchor":96},"ships numpy, GDAL, PyQt",[90,155,156],{"x":149,"y":121,"style":117,"fill":88,"textAnchor":96},"sys.executable in the console",[90,158,159],{"x":149,"y":125,"style":112,"fill":145,"textAnchor":96},"the one that counts",[66,161],{"x":162,"y":163,"width":164,"height":165,"rx":104,"fill":166,"stroke":167,"style":146},"160","204","440","60","#eff3ff","#2563eb",[90,169,172],{"x":92,"y":170,"style":171,"fill":167,"textAnchor":96},"228","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","install with sys.executable -m pip",[90,174,176],{"x":92,"y":175,"style":117,"fill":88,"textAnchor":96},"250","run from the QGIS console, it cannot pick the wrong one",[178,179],"line",{"x1":149,"y1":180,"x2":181,"y2":182,"stroke":88,"style":183},"180","500","200","stroke-width:2;marker-end:url(#pyEnvArrow)",[185,186,188],"h2",{"id":187},"prerequisites","Prerequisites",[190,191,192,200,203],"ul",{},[193,194,195,199],"li",{},[196,197,198],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[193,201,202],{},"The Python console open, and network access for the package index.",[193,204,205],{},"On Windows, the OSGeo4W shell if you prefer installing from a terminal.",[185,207,209],{"id":208},"find-out-which-python-qgis-is-using","Find out which Python QGIS is using",[211,212,217],"pre",{"className":213,"code":214,"language":215,"meta":216,"style":216},"language-python shiki shiki-themes github-dark","import sys\nimport site\n\nprint(sys.executable)\nprint(sys.version)\nprint(site.getusersitepackages())\nprint([p for p in sys.path if \"site-packages\" in p])\n","python","",[18,218,219,231,239,246,256,264,272],{"__ignoreMap":216},[220,221,223,227],"span",{"class":178,"line":222},1,[220,224,226],{"class":225},"snl16","import",[220,228,230],{"class":229},"s95oV"," sys\n",[220,232,234,236],{"class":178,"line":233},2,[220,235,226],{"class":225},[220,237,238],{"class":229}," site\n",[220,240,242],{"class":178,"line":241},3,[220,243,245],{"emptyLinePlaceholder":244},true,"\n",[220,247,249,253],{"class":178,"line":248},4,[220,250,252],{"class":251},"sDLfK","print",[220,254,255],{"class":229},"(sys.executable)\n",[220,257,259,261],{"class":178,"line":258},5,[220,260,252],{"class":251},[220,262,263],{"class":229},"(sys.version)\n",[220,265,267,269],{"class":178,"line":266},6,[220,268,252],{"class":251},[220,270,271],{"class":229},"(site.getusersitepackages())\n",[220,273,275,277,280,283,286,289,292,295,299,302],{"class":178,"line":274},7,[220,276,252],{"class":251},[220,278,279],{"class":229},"([p ",[220,281,282],{"class":225},"for",[220,284,285],{"class":229}," p ",[220,287,288],{"class":225},"in",[220,290,291],{"class":229}," sys.path ",[220,293,294],{"class":225},"if",[220,296,298],{"class":297},"sU2Wk"," \"site-packages\"",[220,300,301],{"class":225}," in",[220,303,304],{"class":229}," p])\n",[14,306,307,310,311,314,315,318,319,322,323,326],{},[196,308,309],{},"Breakdown:"," ",[18,312,313],{},"sys.executable"," in the QGIS console is the interpreter QGIS is running, and it is the only reliable answer — on Windows it is inside the OSGeo4W or standalone installation, on macOS inside the application bundle, on Linux usually ",[18,316,317],{},"\u002Fusr\u002Fbin\u002Fpython3",". ",[18,320,321],{},"getusersitepackages()"," is the per-user folder that is on the path without needing write access to the installation, which is where a ",[18,324,325],{},"--user"," install lands. Printing the site-packages entries on the path shows exactly where an import will be found from, which settles most \"it says the module is not installed\" arguments in one line.",[185,328,330],{"id":329},"install-from-inside-qgis","Install from inside QGIS",[211,332,334],{"className":213,"code":333,"language":215,"meta":216,"style":216},"import subprocess\nimport sys\n\nsubprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"--user\", \"requests\"])\n",[18,335,336,343,349,353],{"__ignoreMap":216},[220,337,338,340],{"class":178,"line":222},[220,339,226],{"class":225},[220,341,342],{"class":229}," subprocess\n",[220,344,345,347],{"class":178,"line":233},[220,346,226],{"class":225},[220,348,230],{"class":229},[220,350,351],{"class":178,"line":241},[220,352,245],{"emptyLinePlaceholder":244},[220,354,355,358,361,364,367,369,372,374,377,379,382],{"class":178,"line":248},[220,356,357],{"class":229},"subprocess.check_call([sys.executable, ",[220,359,360],{"class":297},"\"-m\"",[220,362,363],{"class":229},", ",[220,365,366],{"class":297},"\"pip\"",[220,368,363],{"class":229},[220,370,371],{"class":297},"\"install\"",[220,373,363],{"class":229},[220,375,376],{"class":297},"\"--user\"",[220,378,363],{"class":229},[220,380,381],{"class":297},"\"requests\"",[220,383,384],{"class":229},"])\n",[14,386,387,389,390,393,394,396],{},[196,388,309],{}," Calling pip as a module of a specific interpreter is the one form that cannot install into the wrong place. ",[18,391,392],{},"check_call"," raises on failure so a silent error is impossible, and the output appears in the console where you can read it. ",[18,395,325],{}," installs into the per-user site-packages folder, which needs no administrator rights and — importantly — survives a QGIS upgrade that replaces the installation folder. Restart QGIS afterwards: a package installed into a path Python has already scanned is not always importable until the interpreter restarts.",[14,398,399],{},"For repeatability, keep the list of extra packages in a file and install them together:",[211,401,403],{"className":213,"code":402,"language":215,"meta":216,"style":216},"subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"--user\",\n                       \"-r\", \"\u002Fhome\u002Fana\u002Fgis_requirements.txt\"])\n",[18,404,405,426],{"__ignoreMap":216},[220,406,407,409,411,413,415,417,419,421,423],{"class":178,"line":222},[220,408,357],{"class":229},[220,410,360],{"class":297},[220,412,363],{"class":229},[220,414,366],{"class":297},[220,416,363],{"class":229},[220,418,371],{"class":297},[220,420,363],{"class":229},[220,422,376],{"class":297},[220,424,425],{"class":229},",\n",[220,427,428,431,433,436],{"class":178,"line":233},[220,429,430],{"class":297},"                       \"-r\"",[220,432,363],{"class":229},[220,434,435],{"class":297},"\"\u002Fhome\u002Fana\u002Fgis_requirements.txt\"",[220,437,384],{"class":229},[14,439,440,442,443,446,447,451],{},[196,441,309],{}," A requirements file makes the environment reproducible for a colleague and documents what your scripts actually need, which is otherwise discovered one ",[18,444,445],{},"ImportError"," at a time on somebody else's machine. Pin versions for anything you depend on heavily; leave them loose for utilities. This is also what a container image should install, as covered in ",[43,448,450],{"href":449},"\u002Fpyqgis-fundamentals-environment-setup\u002Fheadless-qgis-and-server-automation\u002Frun-pyqgis-in-docker-container\u002F","Run PyQGIS in a Docker Container",".",[185,453,455],{"id":454},"platform-notes-that-matter","Platform notes that matter",[14,457,458,461,462,465,466,468],{},[196,459,460],{},"Windows."," Use the OSGeo4W shell — it sets the environment so ",[18,463,464],{},"python -m pip"," is the QGIS Python. Installing into the QGIS installation folder often requires administrator rights and is undone by the next upgrade, so prefer ",[18,467,325],{},". Packages with compiled extensions must match the Python version and architecture; a wheel is fine, a source build usually needs tooling that is not present.",[14,470,471,474,475,477],{},[196,472,473],{},"macOS."," The Python inside the application bundle is code-signed, and writing into the bundle can break the signature. A ",[18,476,325],{}," install avoids it entirely.",[14,479,480,483,484,487,488,491,492,494],{},[196,481,482],{},"Linux."," QGIS from a distribution package uses the system Python, and installing there with pip can conflict with the package manager. Prefer the distribution's own package where one exists — ",[18,485,486],{},"python3-pandas"," rather than ",[18,489,490],{},"pip install pandas"," — and ",[18,493,325],{}," otherwise. Newer distributions refuse a system-wide pip install altogether unless you pass a flag, and that refusal is protecting you.",[14,496,497],{},[51,498,501,504,507,510,517,520,527,532,542,547,549,553,557,560,565,569,572,575,577,579,581,584,589],{"viewBox":499,"role":54,"ariaLabel":500,"xmlns":56},"0 0 760 254","Comparison of installing into the QGIS installation folder against installing into the user site packages folder, showing what happens to each after a QGIS upgrade",[58,502,503],{},"What survives the next QGIS upgrade",[62,505,506],{},"Packages installed into the QGIS installation folder are removed when the installation is replaced by an upgrade, so the extra libraries disappear and scripts fail. Packages installed into the per-user site packages folder live outside the installation and remain importable after the upgrade, as long as the Python version has not changed.",[66,508],{"x":68,"y":68,"width":69,"height":509,"fill":71},"254",[73,511,512],{},[76,513,515],{"id":514,"viewBox":79,"refX":80,"refY":81,"markerWidth":82,"markerHeight":82,"orient":83},"upgradeArrow",[85,516],{"d":87,"fill":88},[90,518,519],{"x":92,"y":93,"style":94,"fill":95,"textAnchor":96},"Install where the upgrade cannot reach",[66,521],{"x":522,"y":523,"width":524,"height":525,"rx":104,"fill":105,"stroke":526,"style":146},"20","48","348","184","#b91c1c",[90,528,531],{"x":529,"y":530,"style":171,"fill":526,"textAnchor":96},"194","74","into the installation folder",[66,533],{"x":534,"y":535,"width":536,"height":537,"rx":538,"fill":539,"stroke":540,"style":541},"44","90","300","34","6","#fffdf7","#59645f","stroke-width:1.5",[90,543,546],{"x":165,"y":544,"style":545,"fill":88},"112","font-size:11px;font-family:sans-serif","works immediately",[66,548],{"x":534,"y":110,"width":536,"height":537,"rx":538,"fill":539,"stroke":540,"style":541},[90,550,552],{"x":165,"y":551,"style":545,"fill":88},"154","QGIS is upgraded",[66,554],{"x":534,"y":555,"width":536,"height":556,"rx":538,"fill":71,"stroke":526,"style":107},"174","42",[90,558,559],{"x":529,"y":182,"style":112,"fill":526,"textAnchor":96},"packages gone, scripts fail",[66,561],{"x":562,"y":523,"width":524,"height":525,"rx":104,"fill":563,"stroke":564,"style":146},"392","#edf8e9","#15803d",[90,566,568],{"x":567,"y":530,"style":171,"fill":564,"textAnchor":96},"566","into user site-packages",[66,570],{"x":571,"y":535,"width":536,"height":537,"rx":538,"fill":539,"stroke":540,"style":541},"416",[90,573,546],{"x":574,"y":544,"style":545,"fill":88},"432",[66,576],{"x":571,"y":110,"width":536,"height":537,"rx":538,"fill":539,"stroke":540,"style":541},[90,578,552],{"x":574,"y":551,"style":545,"fill":88},[66,580],{"x":571,"y":555,"width":536,"height":556,"rx":538,"fill":539,"stroke":564,"style":107},[90,582,583],{"x":567,"y":529,"style":112,"fill":564,"textAnchor":96},"still importable",[90,585,588],{"x":567,"y":586,"style":587,"fill":540,"textAnchor":96},"212","text-anchor:middle;font-size:10px;font-family:sans-serif","unless the Python version changed",[178,590],{"x1":591,"y1":592,"x2":593,"y2":592,"stroke":88,"style":594},"368","140","386","stroke-width:2;marker-end:url(#upgradeArrow)",[185,596,598],{"id":597},"do-not-upgrade-what-qgis-depends-on","Do not upgrade what QGIS depends on",[14,600,601],{},"Some packages in the QGIS environment are not ordinary dependencies — they are compiled against the same libraries as QGIS itself, and replacing them breaks the application in ways that are hard to diagnose.",[14,603,604,621,622,624],{},[196,605,606,607,363,610,363,613,616,617,620],{},"Never upgrade ",[18,608,609],{},"numpy",[18,611,612],{},"gdal",[18,614,615],{},"osgeo"," or ",[18,618,619],{},"PyQt"," with pip."," GDAL's Python bindings must match the GDAL C++ library QGIS links against; a mismatched pair produces import errors, silently wrong raster reads, or a crash at startup. ",[18,623,609],{}," is the base of the raster interfaces and is compiled against a specific ABI. PyQt must match the Qt QGIS was built with.",[14,626,627,630,631,633],{},[196,628,629],{},"Be careful with anything that pulls them in as a dependency."," A package requesting a newer ",[18,632,609],{}," will happily upgrade it. Check first:",[211,635,637],{"className":213,"code":636,"language":215,"meta":216,"style":216},"subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"--user\",\n                       \"--dry-run\", \"some-package\"])\n",[18,638,639,659],{"__ignoreMap":216},[220,640,641,643,645,647,649,651,653,655,657],{"class":178,"line":222},[220,642,357],{"class":229},[220,644,360],{"class":297},[220,646,363],{"class":229},[220,648,366],{"class":297},[220,650,363],{"class":229},[220,652,371],{"class":297},[220,654,363],{"class":229},[220,656,376],{"class":297},[220,658,425],{"class":229},[220,660,661,664,666,669],{"class":178,"line":233},[220,662,663],{"class":297},"                       \"--dry-run\"",[220,665,363],{"class":229},[220,667,668],{"class":297},"\"some-package\"",[220,670,384],{"class":229},[14,672,673,310,675,678,679,681,682,684],{},[196,674,309],{},[18,676,677],{},"--dry-run"," reports what would be installed or upgraded without doing it, which is the cheapest possible way to discover that a small utility wants to replace ",[18,680,609],{},". If it does, either pin the version you have with a constraint file, or find a lighter alternative. Recovering from a broken ",[18,683,609],{}," in the QGIS environment usually means reinstalling QGIS, which is a bad afternoon.",[14,686,687],{},[51,688,691,694,697,699,702,704,707,711,715,717,721,724,728,732,734,737,739,742,744,747,749,752],{"viewBox":689,"role":54,"ariaLabel":690,"xmlns":56},"0 0 760 250","Diagram separating packages that are safe to install into the QGIS environment from the compiled dependencies that must never be upgraded with pip",[58,692,693],{},"Safe to add, and never to touch",[62,695,696],{},"Pure Python utilities such as requests, openpyxl and small helper libraries install cleanly into the QGIS environment. Compiled packages that QGIS itself links against — numpy, the GDAL bindings and PyQt — must match the libraries QGIS was built with, so upgrading them with pip breaks the application rather than the package.",[66,698],{"x":68,"y":68,"width":69,"height":175,"fill":71},[90,700,701],{"x":92,"y":93,"style":94,"fill":95,"textAnchor":96},"The dividing line is whether QGIS links against it",[66,703],{"x":522,"y":101,"width":524,"height":180,"rx":104,"fill":563,"stroke":564,"style":146},[90,705,706],{"x":529,"y":111,"style":171,"fill":564,"textAnchor":96},"safe to install",[66,708],{"x":534,"y":709,"width":536,"height":93,"rx":81,"fill":539,"stroke":540,"style":710},"94","stroke-width:1.2",[90,712,714],{"x":165,"y":713,"style":545,"fill":88},"113","requests, httpx — pure Python",[66,716],{"x":534,"y":103,"width":536,"height":93,"rx":81,"fill":539,"stroke":540,"style":710},[90,718,720],{"x":165,"y":719,"style":545,"fill":88},"147","openpyxl, python-docx",[66,722],{"x":534,"y":723,"width":536,"height":93,"rx":81,"fill":539,"stroke":540,"style":710},"162",[90,725,727],{"x":165,"y":726,"style":545,"fill":88},"181","small helper libraries",[90,729,731],{"x":529,"y":730,"style":117,"fill":564,"textAnchor":96},"214","install with --user and restart",[66,733],{"x":562,"y":101,"width":524,"height":180,"rx":104,"fill":105,"stroke":526,"style":146},[90,735,736],{"x":567,"y":111,"style":171,"fill":526,"textAnchor":96},"never upgrade with pip",[66,738],{"x":571,"y":709,"width":536,"height":93,"rx":81,"fill":539,"stroke":526,"style":541},[90,740,741],{"x":574,"y":713,"style":545,"fill":88},"numpy — the raster array interface",[66,743],{"x":571,"y":103,"width":536,"height":93,"rx":81,"fill":539,"stroke":526,"style":541},[90,745,746],{"x":574,"y":719,"style":545,"fill":88},"gdal and osgeo bindings",[66,748],{"x":571,"y":723,"width":536,"height":93,"rx":81,"fill":539,"stroke":526,"style":541},[90,750,751],{"x":574,"y":726,"style":545,"fill":88},"PyQt — must match the Qt build",[90,753,754],{"x":567,"y":730,"style":117,"fill":526,"textAnchor":96},"check dependencies with --dry-run first",[185,756,758],{"id":757},"keep-heavy-work-outside-qgis","Keep heavy work outside QGIS",[14,760,761],{},"Where a project needs a large scientific stack, installing all of it into the QGIS Python is rarely the right answer. Two better shapes exist.",[14,763,764,767],{},[196,765,766],{},"Run the heavy analysis in its own virtual environment"," and have it read and write files — GeoPackages, GeoTIFFs, CSVs — that QGIS then reads. The interchange is a file, the environments stay independent, and neither can break the other.",[14,769,770,773,774,778],{},[196,771,772],{},"Use QGIS as a library from your own environment"," instead, by putting the QGIS Python libraries on that environment's path. This is the standalone-script arrangement described in ",[43,775,777],{"href":776},"\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Frunning-python-scripts-outside-qgis-desktop\u002F","Running Python Scripts Outside QGIS Desktop",", and it lets a data-science environment own the dependency set while still calling PyQGIS.",[14,780,781,782,451],{},"The rule of thumb: install small utilities into the QGIS Python, and keep large stacks in their own environment with files as the boundary. It is the arrangement that survives both a QGIS upgrade and a colleague's ",[18,783,37],{},[185,785,787],{"id":786},"qgis-version-compatibility","QGIS version compatibility",[789,790,791,807],"table",{},[792,793,794],"thead",{},[795,796,797,801,804],"tr",{},[798,799,800],"th",{},"QGIS version",[798,802,803],{},"Python",[798,805,806],{},"Notes",[808,809,810,822,832,843],"tbody",{},[795,811,812,816,819],{},[813,814,815],"td",{},"3.22 LTR",[813,817,818],{},"3.9",[813,820,821],{},"Packages must provide wheels for 3.9; user-site installs work identically.",[795,823,824,827,829],{},[813,825,826],{},"3.28 LTR",[813,828,818],{},[813,830,831],{},"Identical.",[795,833,834,837,840],{},[813,835,836],{},"3.34 LTR",[813,838,839],{},"3.12",[813,841,842],{},"Baseline for this page. User site-packages folder is version-specific.",[795,844,845,848,850],{},[813,846,847],{},"3.40 \u002F 3.44",[813,849,839],{},[813,851,852],{},"Identical mechanism.",[14,854,855],{},"Because the user site folder is per Python version, an upgrade that changes the bundled Python — 3.9 to 3.12, for example — means reinstalling your packages. A requirements file makes that one command instead of an archaeology exercise.",[185,857,859],{"id":858},"troubleshooting","Troubleshooting",[190,861,862,875,883,892,898,904],{},[193,863,864,870,871,874],{},[196,865,866,869],{},[18,867,868],{},"ModuleNotFoundError"," after a successful install."," It went into a different interpreter. Reinstall with ",[18,872,873],{},"sys.executable -m pip"," from the console, and restart QGIS.",[193,876,877,880,881,451],{},[196,878,879],{},"Permission denied."," You are writing into the installation folder. Add ",[18,882,325],{},[193,884,885,888,889,891],{},[196,886,887],{},"The install succeeds but QGIS crashes on start."," A core dependency was upgraded. Reinstall QGIS and use ",[18,890,677],{}," next time.",[193,893,894,897],{},[196,895,896],{},"A compiled package will not build."," No wheel for your platform and Python version. Look for a distribution package, or a pure-Python alternative.",[193,899,900,903],{},[196,901,902],{},"It works for you and not for a colleague."," Nobody wrote the requirements down. Keep a requirements file next to the scripts.",[193,905,906,909],{},[196,907,908],{},"Packages disappear after an upgrade."," They were in the installation folder, or the Python version changed. Reinstall from your requirements file.",[185,911,913],{"id":912},"conclusion","Conclusion",[14,915,916,917,919,920,923,924,363,926,616,928,930,931,933],{},"Find the interpreter with ",[18,918,313],{}," in the QGIS console, install with ",[18,921,922],{},"sys.executable -m pip install --user",", and restart QGIS. Keep a requirements file so the environment is reproducible, never let pip upgrade ",[18,925,609],{},[18,927,612],{},[18,929,619],{},", and check with ",[18,932,677],{}," when a package's dependencies are unknown. For anything heavier than a utility, keep the stack in its own environment and exchange files.",[185,935,937],{"id":936},"frequently-asked-questions","Frequently Asked Questions",[14,939,940,943],{},[196,941,942],{},"Can I use a virtual environment with QGIS?","\nNot as QGIS's own interpreter. You can go the other way — add the QGIS libraries to your environment's path and use PyQGIS from it, which is the standalone-script arrangement.",[14,945,946,949],{},[196,947,948],{},"Is there a plugin that installs packages?","\nSeveral exist and they run the same pip command for you. Doing it explicitly is one line and leaves you knowing what happened.",[14,951,952,955],{},[196,953,954],{},"How do I install a package for all users on a shared machine?","\nInto the installation's site-packages with administrator rights, accepting that an upgrade will remove it. A managed image or a container is a better answer at that scale.",[14,957,958,961],{},[196,959,960],{},"Why does QGIS ship its own numpy?","\nBecause the raster interfaces exchange arrays with it and must agree on the binary layout. That is precisely why replacing it breaks things.",[14,963,964,967],{},[196,965,966],{},"Can I use conda?","\nYes, for a QGIS installed from conda-forge, where the whole stack is managed together. Mixing a conda environment with a system-installed QGIS is where the trouble starts.",[14,969,970,973,974,977,978,451],{},[196,971,972],{},"Do plugins with dependencies handle this themselves?","\nWell-behaved ones declare requirements in ",[18,975,976],{},"metadata.txt"," and fail with a clear message rather than installing silently — see ",[43,979,981],{"href":980},"\u002Fqgis-plugin-development\u002Fpublishing-to-the-qgis-plugin-repository\u002Fwrite-metadata-txt-qgis-plugin\u002F","Write metadata.txt for a QGIS Plugin",[185,983,985],{"id":984},"related","Related",[190,987,988,993,997,1003,1007],{},[193,989,990,992],{},[43,991,46],{"href":45}," — the guide this recipe belongs to",[193,994,995],{},[43,996,777],{"href":776},[193,998,999],{},[43,1000,1002],{"href":1001},"\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Fuse-pyqgis-in-jupyter-notebook\u002F","Use PyQGIS in a Jupyter Notebook",[193,1004,1005],{},[43,1006,450],{"href":449},[193,1008,1009],{},[43,1010,1012],{"href":1011},"\u002Fpyqgis-fundamentals-environment-setup\u002Fdebugging-pyqgis-scripts\u002Ffixing-pyqgis-module-import-errors\u002F","Fixing PyQGIS Module Import Errors",[1014,1015,1016],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":216,"searchDepth":233,"depth":233,"links":1018},[1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029],{"id":187,"depth":233,"text":188},{"id":208,"depth":233,"text":209},{"id":329,"depth":233,"text":330},{"id":454,"depth":233,"text":455},{"id":597,"depth":233,"text":598},{"id":757,"depth":233,"text":758},{"id":786,"depth":233,"text":787},{"id":858,"depth":233,"text":859},{"id":912,"depth":233,"text":913},{"id":936,"depth":233,"text":937},{"id":984,"depth":233,"text":985},"Add pandas, requests or any other library to the Python QGIS actually uses — the right pip invocation per platform, user-site installs that survive upgrades, and how to avoid breaking the bundled numpy or GDAL.","md",{"slug":1033,"type":1034,"breadcrumb":1035,"datePublished":1036,"dateModified":1036},"install-python-packages-into-qgis","article","Install Packages","2026-08-15","\u002Fpyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Finstall-python-packages-into-qgis",{"title":5,"description":1030},"pyqgis-fundamentals-environment-setup\u002Fvirtual-environments-for-gis\u002Finstall-python-packages-into-qgis\u002Findex","6MqoTikEeVZDeZjr7FN2LbSMBDu1JssZySbYYao8bAM",1786789584630]