[{"data":1,"prerenderedAt":1855},["ShallowReactive",2],{"doc:\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fcreate-memory-layer-pyqgis":3},{"id":4,"title":5,"body":6,"description":1844,"extension":1845,"meta":1846,"navigation":254,"path":1851,"seo":1852,"stem":1853,"__hash__":1854},"docs\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fcreate-memory-layer-pyqgis\u002Findex.md","Create a Memory Layer in PyQGIS",{"type":7,"value":8,"toc":1831},"minimark",[9,13,17,26,182,187,215,219,222,383,476,583,587,590,921,958,975,979,986,1061,1252,1270,1274,1277,1437,1457,1468,1472,1475,1609,1629,1633,1672,1676,1723,1727,1739,1743,1749,1766,1778,1794,1798,1827],[10,11,5],"h1",{"id":12},"create-a-memory-layer-in-pyqgis",[14,15,16],"p",{},"A memory layer is a vector layer whose features live only in RAM. Nothing is written to disk, nothing needs a path, and creating one takes a single line. That makes it the natural scratch surface for a script: intermediate results between Processing steps, points generated from an API response, a selection you want to style separately, or the output of a quick experiment in the Python console.",[14,18,19,20,25],{},"This recipe belongs to ",[21,22,24],"a",{"href":23},"\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002F","Features, Geometries & Memory Layers",". It shows how to declare a memory layer completely in its URI, add fields and features efficiently, copy the schema of an existing layer, and turn the temporary layer into a permanent file before the work is lost.",[14,27,28],{},[29,30,35,39,43,50,67,76,85,91,96,100,107,112,116,120,124,128,134,139,142,145,152,157,161,164,168,171,177],"svg",{"viewBox":31,"role":32,"ariaLabel":33,"xmlns":34},"0 0 760 280","img","Life of a memory layer: created from a URI with geometry type, CRS and fields, holding features in RAM, used like any layer, and lost on close unless saved to a GeoPackage","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[36,37,38],"title",{},"What a memory layer is",[40,41,42],"desc",{},"A memory layer is created from a URI string that names the geometry type, the CRS and the fields. Its features are held by the memory provider in RAM. It behaves like any other vector layer for styling, Processing and editing, but when the project is closed the features disappear unless they are saved to a file such as a GeoPackage.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","760","280","#f6f3ea",[51,52,53],"defs",{},[54,55,62],"marker",{"id":56,"viewBox":57,"refX":58,"refY":59,"markerWidth":60,"markerHeight":60,"orient":61},"memLifeArrow","0 0 10 10","8","5","7","auto-start-reverse",[63,64],"path",{"d":65,"fill":66},"M0 0 L10 5 L0 10 z","#2f3b35",[68,69,75],"text",{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"380","28","text-anchor:middle;font-size:14px;font-family:sans-serif;font-weight:bold","#17211d","middle","Everything in RAM until you save it",[44,77],{"x":78,"y":79,"width":80,"height":81,"rx":58,"fill":82,"stroke":83,"style":84},"24","60","200","92","#eef7f4","#0f766e","stroke-width:2",[68,86,90],{"x":87,"y":88,"style":89,"fill":83,"textAnchor":74},"124","89.83","text-anchor:middle;font-size:11.5px;font-family:sans-serif;font-weight:bold","URI",[68,92,95],{"x":87,"y":93,"style":94,"fill":66,"textAnchor":74},"109.78","text-anchor:middle;font-size:10.0px;font-family:monospace","Point?crs=EPSG:25832",[68,97,99],{"x":87,"y":98,"style":94,"fill":66,"textAnchor":74},"129.73","&field=name:string",[101,102],"line",{"x1":103,"y1":104,"x2":105,"y2":104,"stroke":66,"style":106},"224","106","270","stroke-width:1.8;marker-end:url(#memLifeArrow)",[44,108],{"x":109,"y":79,"width":80,"height":81,"rx":58,"fill":110,"stroke":111,"style":84},"278","#eff3ff","#2563eb",[68,113,115],{"x":114,"y":88,"style":89,"fill":111,"textAnchor":74},"378","memory provider",[68,117,119],{"x":114,"y":93,"style":118,"fill":66,"textAnchor":74},"text-anchor:middle;font-size:10.5px;font-family:sans-serif","features in RAM",[68,121,123],{"x":114,"y":98,"style":118,"fill":122,"textAnchor":74},"#59645f","no path, no file lock",[101,125],{"x1":126,"y1":104,"x2":127,"y2":104,"stroke":66,"style":106},"478","524",[44,129],{"x":130,"y":79,"width":131,"height":81,"rx":58,"fill":132,"stroke":133,"style":84},"532","204","#e8efe6","#15803d",[68,135,138],{"x":136,"y":88,"style":89,"fill":137,"textAnchor":74},"634","#166534","any layer API",[68,140,141],{"x":136,"y":93,"style":118,"fill":66,"textAnchor":74},"style · edit · Processing",[68,143,144],{"x":136,"y":98,"style":118,"fill":122,"textAnchor":74},"same as a file layer",[44,146],{"x":147,"y":148,"width":80,"height":149,"rx":58,"fill":150,"stroke":151,"style":84},"160","190","64","#fdf2e2","#b91c1c",[68,153,156],{"x":154,"y":155,"style":89,"fill":151,"textAnchor":74},"260","215.805","project closed",[68,158,160],{"x":154,"y":159,"style":118,"fill":122,"textAnchor":74},"235.755","features gone",[44,162],{"x":163,"y":148,"width":80,"height":149,"rx":58,"fill":132,"stroke":133,"style":84},"400",[68,165,167],{"x":166,"y":155,"style":89,"fill":137,"textAnchor":74},"500","savefeatures",[68,169,170],{"x":166,"y":159,"style":94,"fill":66,"textAnchor":74},"result.gpkg",[101,172],{"x1":173,"y1":174,"x2":175,"y2":176,"stroke":66,"style":106},"610","152","520","188",[101,178],{"x1":179,"y1":174,"x2":180,"y2":176,"stroke":66,"style":181},"560","330","stroke-width:1.8;marker-end:url(#memLifeArrow);stroke-dasharray:5 4",[183,184,186],"h2",{"id":185},"prerequisites","Prerequisites",[188,189,190,199],"ul",{},[191,192,193,194,198],"li",{},"QGIS 3.34 LTR, 3.40 LTR or the QGIS 4 series. The code runs unchanged in the Python console, a script in the Python editor, or a standalone script with an initialised ",[195,196,197],"code",{},"QgsApplication",".",[191,200,201,202,205,206,209,210,214],{},"Basic familiarity with ",[195,203,204],{},"QgsVectorLayer"," and ",[195,207,208],{},"QgsFeature",". If those are new, read ",[21,211,213],{"href":212},"\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fadd-features-to-vector-layer-pyqgis\u002F","adding features to a vector layer"," alongside this page.",[183,216,218],{"id":217},"declare-the-layer-in-its-uri","Declare the layer in its URI",[14,220,221],{},"The memory provider takes everything it needs from a URI string. The part before the question mark is the geometry type; the query parameters set the CRS, the fields and, optionally, a spatial index. Declaring all of it up front means the layer is complete the moment it exists.",[223,224,229],"pre",{"className":225,"code":226,"language":227,"meta":228,"style":228},"language-python shiki shiki-themes github-dark","from qgis.core import QgsVectorLayer, QgsProject\n\nuri = (\n    \"Point?crs=EPSG:25832\"\n    \"&field=id:integer\"\n    \"&field=name:string(80)\"\n    \"&field=height_m:double(10,2)\"\n    \"&field=surveyed:date\"\n    \"&index=yes\"\n)\nmasts = QgsVectorLayer(uri, \"masts\", \"memory\")\nif not masts.isValid():\n    raise RuntimeError(\"memory layer could not be created\")\n\nprint(masts.wkbType(), masts.crs().authid(), masts.fields().names())\nQgsProject.instance().addMapLayer(masts)\n","python","",[195,230,231,249,256,268,275,281,287,293,299,305,311,333,345,363,368,377],{"__ignoreMap":228},[232,233,235,239,243,246],"span",{"class":101,"line":234},1,[232,236,238],{"class":237},"snl16","from",[232,240,242],{"class":241},"s95oV"," qgis.core ",[232,244,245],{"class":237},"import",[232,247,248],{"class":241}," QgsVectorLayer, QgsProject\n",[232,250,252],{"class":101,"line":251},2,[232,253,255],{"emptyLinePlaceholder":254},true,"\n",[232,257,259,262,265],{"class":101,"line":258},3,[232,260,261],{"class":241},"uri ",[232,263,264],{"class":237},"=",[232,266,267],{"class":241}," (\n",[232,269,271],{"class":101,"line":270},4,[232,272,274],{"class":273},"sU2Wk","    \"Point?crs=EPSG:25832\"\n",[232,276,278],{"class":101,"line":277},5,[232,279,280],{"class":273},"    \"&field=id:integer\"\n",[232,282,284],{"class":101,"line":283},6,[232,285,286],{"class":273},"    \"&field=name:string(80)\"\n",[232,288,290],{"class":101,"line":289},7,[232,291,292],{"class":273},"    \"&field=height_m:double(10,2)\"\n",[232,294,296],{"class":101,"line":295},8,[232,297,298],{"class":273},"    \"&field=surveyed:date\"\n",[232,300,302],{"class":101,"line":301},9,[232,303,304],{"class":273},"    \"&index=yes\"\n",[232,306,308],{"class":101,"line":307},10,[232,309,310],{"class":241},")\n",[232,312,314,317,319,322,325,328,331],{"class":101,"line":313},11,[232,315,316],{"class":241},"masts ",[232,318,264],{"class":237},[232,320,321],{"class":241}," QgsVectorLayer(uri, ",[232,323,324],{"class":273},"\"masts\"",[232,326,327],{"class":241},", ",[232,329,330],{"class":273},"\"memory\"",[232,332,310],{"class":241},[232,334,336,339,342],{"class":101,"line":335},12,[232,337,338],{"class":237},"if",[232,340,341],{"class":237}," not",[232,343,344],{"class":241}," masts.isValid():\n",[232,346,348,351,355,358,361],{"class":101,"line":347},13,[232,349,350],{"class":237},"    raise",[232,352,354],{"class":353},"sDLfK"," RuntimeError",[232,356,357],{"class":241},"(",[232,359,360],{"class":273},"\"memory layer could not be created\"",[232,362,310],{"class":241},[232,364,366],{"class":101,"line":365},14,[232,367,255],{"emptyLinePlaceholder":254},[232,369,371,374],{"class":101,"line":370},15,[232,372,373],{"class":353},"print",[232,375,376],{"class":241},"(masts.wkbType(), masts.crs().authid(), masts.fields().names())\n",[232,378,380],{"class":101,"line":379},16,[232,381,382],{"class":241},"QgsProject.instance().addMapLayer(masts)\n",[14,384,385,389,390,327,393,327,396,399,400,403,404,327,407,205,410,413,414,417,418,421,422,425,426,429,430,327,433,436,437,327,440,327,443,327,446,327,449,327,452,455,456,459,460,463,464,467,468,471,472,475],{},[386,387,388],"strong",{},"Breakdown:"," The geometry part accepts ",[195,391,392],{},"Point",[195,394,395],{},"LineString",[195,397,398],{},"Polygon",", their ",[195,401,402],{},"Multi"," forms, the ",[195,405,406],{},"Z",[195,408,409],{},"M",[195,411,412],{},"ZM"," variants (for example ",[195,415,416],{},"PointZ"," or ",[195,419,420],{},"MultiPolygonZM","), and ",[195,423,424],{},"None"," for an attribute-only table. Field definitions are ",[195,427,428],{},"name:type(length,precision)",", with types ",[195,431,432],{},"integer",[195,434,435],{},"int8"," (64-bit), ",[195,438,439],{},"double",[195,441,442],{},"string",[195,444,445],{},"date",[195,447,448],{},"time",[195,450,451],{},"datetime",[195,453,454],{},"bool"," and, on recent releases, ",[195,457,458],{},"binary"," and list types such as ",[195,461,462],{},"stringlist",". ",[195,465,466],{},"index=yes"," builds a spatial index the provider keeps up to date as you add features, which makes later ",[195,469,470],{},"setFilterRect"," requests fast. Always pass ",[195,473,474],{},"crs="," explicitly: a memory layer without it has an invalid CRS and will be placed wherever the project guesses.",[14,477,478],{},[29,479,482,485,488,491,494,500,504,508,513,517,521,525,527,530,533,536,539,543,547,550,553,556,560,564,567,570,573,577,579,581],{"viewBox":480,"role":32,"ariaLabel":481,"xmlns":34},"0 0 760 250","A memory layer URI split into its parts: geometry type, CRS, repeated field definitions and the spatial index flag",[36,483,484],{},"Anatomy of a memory layer URI",[40,486,487],{},"The URI MultiPolygonZ?crs=EPSG:3035&field=code:string(10)&field=pop:int8&index=yes is split into four parts: geometry type and dimensions before the question mark, the CRS parameter, repeated field parameters each with name, type and optional length, and the optional spatial index flag.",[44,489],{"x":46,"y":46,"width":47,"height":490,"fill":49},"250",[68,492,493],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"One string declares the whole layer",[44,495],{"x":78,"y":496,"width":497,"height":498,"rx":58,"fill":499,"stroke":122,"style":84},"52","712","44","#fffdf7",[68,501,503],{"x":70,"y":502,"style":94,"fill":66,"textAnchor":74},"77.78","MultiPolygonZ?crs=EPSG:3035&field=code:string(10)&field=pop:int8&index=yes",[44,505],{"x":78,"y":506,"width":147,"height":507,"rx":58,"fill":82,"stroke":83,"style":84},"128","100",[68,509,512],{"x":510,"y":511,"style":89,"fill":83,"textAnchor":74},"104","151.855","geometry",[68,514,516],{"x":510,"y":515,"style":118,"fill":66,"textAnchor":74},"171.805","MultiPolygonZ",[68,518,520],{"x":510,"y":519,"style":118,"fill":122,"textAnchor":74},"191.755","Point, LineString,",[68,522,524],{"x":510,"y":523,"style":118,"fill":122,"textAnchor":74},"211.705","None, …Z, …M",[44,526],{"x":80,"y":506,"width":147,"height":507,"rx":58,"fill":110,"stroke":111,"style":84},[68,528,529],{"x":48,"y":511,"style":89,"fill":111,"textAnchor":74},"crs",[68,531,532],{"x":48,"y":515,"style":118,"fill":66,"textAnchor":74},"EPSG:3035",[68,534,535],{"x":48,"y":519,"style":118,"fill":122,"textAnchor":74},"authid, WKT",[68,537,538],{"x":48,"y":523,"style":118,"fill":122,"textAnchor":74},"or proj string",[44,540],{"x":541,"y":506,"width":80,"height":507,"rx":58,"fill":150,"stroke":542,"style":84},"376","#b45309",[68,544,546],{"x":545,"y":511,"style":89,"fill":542,"textAnchor":74},"476","field (repeat)",[68,548,549],{"x":545,"y":515,"style":118,"fill":66,"textAnchor":74},"name:type(len,prec)",[68,551,552],{"x":545,"y":519,"style":118,"fill":122,"textAnchor":74},"string, int8, double,",[68,554,555],{"x":545,"y":523,"style":118,"fill":122,"textAnchor":74},"date, datetime, bool",[44,557],{"x":558,"y":506,"width":559,"height":507,"rx":58,"fill":132,"stroke":133,"style":84},"592","144",[68,561,563],{"x":562,"y":511,"style":89,"fill":137,"textAnchor":74},"664","index",[68,565,566],{"x":562,"y":515,"style":118,"fill":66,"textAnchor":74},"yes",[68,568,569],{"x":562,"y":519,"style":118,"fill":122,"textAnchor":74},"spatial index",[68,571,572],{"x":562,"y":523,"style":118,"fill":122,"textAnchor":74},"kept current",[101,574],{"x1":510,"y1":575,"x2":510,"y2":506,"stroke":122,"style":576},"96","stroke-width:1.5",[101,578],{"x1":48,"y1":575,"x2":48,"y2":506,"stroke":122,"style":576},[101,580],{"x1":545,"y1":575,"x2":545,"y2":506,"stroke":122,"style":576},[101,582],{"x1":562,"y1":575,"x2":562,"y2":506,"stroke":122,"style":576},[183,584,586],{"id":585},"add-fields-and-features-in-bulk","Add fields and features in bulk",[14,588,589],{},"Fields can also be added after creation through the data provider, which is convenient when the schema is computed rather than known in advance. Features should then be added in one call rather than in a loop of single additions.",[223,591,593],{"className":225,"code":592,"language":227,"meta":228,"style":228},"from qgis.core import QgsField, QgsFeature, QgsGeometry, QgsPointXY\nfrom qgis.PyQt.QtCore import QVariant, QDate\n\nprovider = masts.dataProvider()\nprovider.addAttributes([QgsField(\"operator\", QVariant.String, len=40)])\nmasts.updateFields()\n\nrows = [\n    (1, \"Hochberg\", 412.5, QDate(2025, 6, 3), \"NetCo\", 571230.0, 5934010.0),\n    (2, \"Kalkwerk\", 388.0, QDate(2025, 6, 4), \"NetCo\", 573980.0, 5931475.0),\n    (3, \"Seeblick\", 405.2, QDate(2025, 6, 9), \"AirLink\", 569410.0, 5929920.0),\n]\nfeatures = []\nfor mid, name, height, when, op, x, y in rows:\n    f = QgsFeature(masts.fields())\n    f.setAttributes([mid, name, height, when, op])\n    f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))\n    features.append(f)\n\nok, added = provider.addFeatures(features)\nmasts.updateExtents()\nprint(ok, len(added), \"features; extent\", masts.extent().toString(1))\n",[195,594,595,606,618,622,632,655,660,664,674,727,773,819,824,834,848,858,863,869,875,880,891,897],{"__ignoreMap":228},[232,596,597,599,601,603],{"class":101,"line":234},[232,598,238],{"class":237},[232,600,242],{"class":241},[232,602,245],{"class":237},[232,604,605],{"class":241}," QgsField, QgsFeature, QgsGeometry, QgsPointXY\n",[232,607,608,610,613,615],{"class":101,"line":251},[232,609,238],{"class":237},[232,611,612],{"class":241}," qgis.PyQt.QtCore ",[232,614,245],{"class":237},[232,616,617],{"class":241}," QVariant, QDate\n",[232,619,620],{"class":101,"line":258},[232,621,255],{"emptyLinePlaceholder":254},[232,623,624,627,629],{"class":101,"line":270},[232,625,626],{"class":241},"provider ",[232,628,264],{"class":237},[232,630,631],{"class":241}," masts.dataProvider()\n",[232,633,634,637,640,643,647,649,652],{"class":101,"line":277},[232,635,636],{"class":241},"provider.addAttributes([QgsField(",[232,638,639],{"class":273},"\"operator\"",[232,641,642],{"class":241},", QVariant.String, ",[232,644,646],{"class":645},"s9osk","len",[232,648,264],{"class":237},[232,650,651],{"class":353},"40",[232,653,654],{"class":241},")])\n",[232,656,657],{"class":101,"line":283},[232,658,659],{"class":241},"masts.updateFields()\n",[232,661,662],{"class":101,"line":289},[232,663,255],{"emptyLinePlaceholder":254},[232,665,666,669,671],{"class":101,"line":295},[232,667,668],{"class":241},"rows ",[232,670,264],{"class":237},[232,672,673],{"class":241}," [\n",[232,675,676,679,682,684,687,689,692,695,698,700,703,705,708,711,714,716,719,721,724],{"class":101,"line":301},[232,677,678],{"class":241},"    (",[232,680,681],{"class":353},"1",[232,683,327],{"class":241},[232,685,686],{"class":273},"\"Hochberg\"",[232,688,327],{"class":241},[232,690,691],{"class":353},"412.5",[232,693,694],{"class":241},", QDate(",[232,696,697],{"class":353},"2025",[232,699,327],{"class":241},[232,701,702],{"class":353},"6",[232,704,327],{"class":241},[232,706,707],{"class":353},"3",[232,709,710],{"class":241},"), ",[232,712,713],{"class":273},"\"NetCo\"",[232,715,327],{"class":241},[232,717,718],{"class":353},"571230.0",[232,720,327],{"class":241},[232,722,723],{"class":353},"5934010.0",[232,725,726],{"class":241},"),\n",[232,728,729,731,734,736,739,741,744,746,748,750,752,754,757,759,761,763,766,768,771],{"class":101,"line":307},[232,730,678],{"class":241},[232,732,733],{"class":353},"2",[232,735,327],{"class":241},[232,737,738],{"class":273},"\"Kalkwerk\"",[232,740,327],{"class":241},[232,742,743],{"class":353},"388.0",[232,745,694],{"class":241},[232,747,697],{"class":353},[232,749,327],{"class":241},[232,751,702],{"class":353},[232,753,327],{"class":241},[232,755,756],{"class":353},"4",[232,758,710],{"class":241},[232,760,713],{"class":273},[232,762,327],{"class":241},[232,764,765],{"class":353},"573980.0",[232,767,327],{"class":241},[232,769,770],{"class":353},"5931475.0",[232,772,726],{"class":241},[232,774,775,777,779,781,784,786,789,791,793,795,797,799,802,804,807,809,812,814,817],{"class":101,"line":313},[232,776,678],{"class":241},[232,778,707],{"class":353},[232,780,327],{"class":241},[232,782,783],{"class":273},"\"Seeblick\"",[232,785,327],{"class":241},[232,787,788],{"class":353},"405.2",[232,790,694],{"class":241},[232,792,697],{"class":353},[232,794,327],{"class":241},[232,796,702],{"class":353},[232,798,327],{"class":241},[232,800,801],{"class":353},"9",[232,803,710],{"class":241},[232,805,806],{"class":273},"\"AirLink\"",[232,808,327],{"class":241},[232,810,811],{"class":353},"569410.0",[232,813,327],{"class":241},[232,815,816],{"class":353},"5929920.0",[232,818,726],{"class":241},[232,820,821],{"class":101,"line":335},[232,822,823],{"class":241},"]\n",[232,825,826,829,831],{"class":101,"line":347},[232,827,828],{"class":241},"features ",[232,830,264],{"class":237},[232,832,833],{"class":241}," []\n",[232,835,836,839,842,845],{"class":101,"line":365},[232,837,838],{"class":237},"for",[232,840,841],{"class":241}," mid, name, height, when, op, x, y ",[232,843,844],{"class":237},"in",[232,846,847],{"class":241}," rows:\n",[232,849,850,853,855],{"class":101,"line":370},[232,851,852],{"class":241},"    f ",[232,854,264],{"class":237},[232,856,857],{"class":241}," QgsFeature(masts.fields())\n",[232,859,860],{"class":101,"line":379},[232,861,862],{"class":241},"    f.setAttributes([mid, name, height, when, op])\n",[232,864,866],{"class":101,"line":865},17,[232,867,868],{"class":241},"    f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))\n",[232,870,872],{"class":101,"line":871},18,[232,873,874],{"class":241},"    features.append(f)\n",[232,876,878],{"class":101,"line":877},19,[232,879,255],{"emptyLinePlaceholder":254},[232,881,883,886,888],{"class":101,"line":882},20,[232,884,885],{"class":241},"ok, added ",[232,887,264],{"class":237},[232,889,890],{"class":241}," provider.addFeatures(features)\n",[232,892,894],{"class":101,"line":893},21,[232,895,896],{"class":241},"masts.updateExtents()\n",[232,898,900,902,905,907,910,913,916,918],{"class":101,"line":899},22,[232,901,373],{"class":353},[232,903,904],{"class":241},"(ok, ",[232,906,646],{"class":353},[232,908,909],{"class":241},"(added), ",[232,911,912],{"class":273},"\"features; extent\"",[232,914,915],{"class":241},", masts.extent().toString(",[232,917,681],{"class":353},[232,919,920],{"class":241},"))\n",[14,922,923,925,926,929,930,933,934,937,938,941,942,945,946,949,950,953,954,957],{},[386,924,388],{}," ",[195,927,928],{},"updateFields()"," makes the layer pick up attributes added through the provider; skip it and ",[195,931,932],{},"masts.fields()"," still reports the old schema, so ",[195,935,936],{},"QgsFeature(masts.fields())"," creates features one attribute short. Creating each feature from the layer's fields gives it the right number of attribute slots and lets you use ",[195,939,940],{},"f[\"name\"] = …"," by name. ",[195,943,944],{},"addFeatures"," returns a success flag and the features with their new ids. ",[195,947,948],{},"updateExtents()"," matters for memory layers specifically: without it the cached extent is empty and \"zoom to layer\" goes nowhere. On QGIS 4 builds based on Qt6, use ",[195,951,952],{},"QMetaType.Type.QString"," and friends instead of ",[195,955,956],{},"QVariant.String"," — see the compatibility notes below.",[14,959,960,961,327,964,205,967,970,971,198],{},"Writing through the provider bypasses the edit buffer, which is what you want for a script that builds a layer from scratch. When the user should be able to undo the additions, or when you are adding to a layer that is already in edit mode, use ",[195,962,963],{},"masts.startEditing()",[195,965,966],{},"masts.addFeatures(...)",[195,968,969],{},"masts.commitChanges()"," instead, as described in ",[21,972,974],{"href":973},"\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fundo-edits-with-edit-buffer-pyqgis\u002F","undoing edits with the edit buffer",[183,976,978],{"id":977},"clone-the-schema-of-an-existing-layer","Clone the schema of an existing layer",[14,980,981,982,985],{},"A common need is a memory layer that looks exactly like an existing one — same geometry type, CRS and fields — but holds a filtered or modified copy. ",[195,983,984],{},"QgsMemoryProviderUtils"," builds it directly from those three properties.",[14,987,988],{},[29,989,992,995,998,1001,1008,1011,1015,1019,1023,1027,1031,1035,1040,1044,1048,1051,1055,1058],{"viewBox":990,"role":32,"ariaLabel":991,"xmlns":34},"0 0 760 240","Two routes to a memory copy of an existing layer: an empty layer with the same schema filled by a script, or materialize with a feature request that returns a filled copy",[36,993,994],{},"Two ways to copy a layer into memory",[40,996,997],{},"Left path: QgsMemoryProviderUtils.createMemoryLayer takes the fields, geometry type and CRS of a source layer and returns an empty layer with the same schema, which a script fills with selected or modified features. Right path: materialize with a QgsFeatureRequest returns a filled copy of matching features in one call. Both produce a memory layer that is independent of the source.",[44,999],{"x":46,"y":46,"width":47,"height":1000,"fill":49},"240",[51,1002,1003],{},[54,1004,1006],{"id":1005,"viewBox":57,"refX":58,"refY":59,"markerWidth":60,"markerHeight":60,"orient":61},"memCloneArrow",[63,1007],{"d":65,"fill":66},[68,1009,1010],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"Empty schema copy, or a filled snapshot",[44,1012],{"x":1013,"y":496,"width":1014,"height":496,"rx":58,"fill":499,"stroke":122,"style":84},"290","180",[68,1016,1018],{"x":70,"y":1017,"style":89,"fill":73,"textAnchor":74},"71.805","source layer",[68,1020,1022],{"x":70,"y":1021,"style":118,"fill":122,"textAnchor":74},"91.755","roads.gpkg",[101,1024],{"x1":180,"y1":510,"x2":148,"y2":1025,"stroke":66,"style":1026},"136","stroke-width:1.8;marker-end:url(#memCloneArrow)",[101,1028],{"x1":1029,"y1":510,"x2":1030,"y2":1025,"stroke":66,"style":1026},"430","570",[44,1032],{"x":78,"y":1033,"width":180,"height":1034,"rx":58,"fill":82,"stroke":83,"style":84},"140","80",[68,1036,1039],{"x":1037,"y":1038,"style":89,"fill":83,"textAnchor":74},"189","163.83","createMemoryLayer(…)",[68,1041,1043],{"x":1037,"y":1042,"style":94,"fill":66,"textAnchor":74},"183.78","fields() · wkbType() · crs()",[68,1045,1047],{"x":1037,"y":1046,"style":118,"fill":122,"textAnchor":74},"203.73","empty — you add features",[44,1049],{"x":1050,"y":1033,"width":180,"height":1034,"rx":58,"fill":110,"stroke":111,"style":84},"406",[68,1052,1054],{"x":1053,"y":1038,"style":89,"fill":111,"textAnchor":74},"571","materialize(request)",[68,1056,1057],{"x":1053,"y":1042,"style":94,"fill":66,"textAnchor":74},"QgsFeatureRequest(expression)",[68,1059,1060],{"x":1053,"y":1046,"style":118,"fill":122,"textAnchor":74},"filled copy in one call",[223,1062,1064],{"className":225,"code":1063,"language":227,"meta":228,"style":228},"from qgis.core import (QgsMemoryProviderUtils, QgsFeatureRequest,\n                       QgsVectorLayer, QgsProject)\n\nroads = QgsProject.instance().mapLayersByName(\"roads\")[0]\n\n# 1. an empty layer with the same schema, filled by your own logic\ncopy = QgsMemoryProviderUtils.createMemoryLayer(\n    \"roads (edited copy)\", roads.fields(), roads.wkbType(), roads.crs())\nrequest = QgsFeatureRequest().setFilterExpression(\"\\\"class\\\" = 'primary'\")\nbatch = []\nfor f in roads.getFeatures(request):\n    f.setGeometry(f.geometry().simplify(2.0))\n    batch.append(f)\ncopy.dataProvider().addFeatures(batch)\ncopy.updateExtents()\n\n# 2. a filled snapshot in one call\nsnapshot = roads.materialize(QgsFeatureRequest().setFilterExpression(\"\\\"class\\\" = 'primary'\"))\nsnapshot.setName(\"primary roads (snapshot)\")\nQgsProject.instance().addMapLayers([copy, snapshot])\n",[195,1065,1066,1077,1082,1086,1106,1110,1116,1126,1134,1160,1169,1181,1191,1196,1201,1206,1210,1215,1237,1247],{"__ignoreMap":228},[232,1067,1068,1070,1072,1074],{"class":101,"line":234},[232,1069,238],{"class":237},[232,1071,242],{"class":241},[232,1073,245],{"class":237},[232,1075,1076],{"class":241}," (QgsMemoryProviderUtils, QgsFeatureRequest,\n",[232,1078,1079],{"class":101,"line":251},[232,1080,1081],{"class":241},"                       QgsVectorLayer, QgsProject)\n",[232,1083,1084],{"class":101,"line":258},[232,1085,255],{"emptyLinePlaceholder":254},[232,1087,1088,1091,1093,1096,1099,1102,1104],{"class":101,"line":270},[232,1089,1090],{"class":241},"roads ",[232,1092,264],{"class":237},[232,1094,1095],{"class":241}," QgsProject.instance().mapLayersByName(",[232,1097,1098],{"class":273},"\"roads\"",[232,1100,1101],{"class":241},")[",[232,1103,46],{"class":353},[232,1105,823],{"class":241},[232,1107,1108],{"class":101,"line":277},[232,1109,255],{"emptyLinePlaceholder":254},[232,1111,1112],{"class":101,"line":283},[232,1113,1115],{"class":1114},"sjoCn","# 1. an empty layer with the same schema, filled by your own logic\n",[232,1117,1118,1121,1123],{"class":101,"line":289},[232,1119,1120],{"class":241},"copy ",[232,1122,264],{"class":237},[232,1124,1125],{"class":241}," QgsMemoryProviderUtils.createMemoryLayer(\n",[232,1127,1128,1131],{"class":101,"line":295},[232,1129,1130],{"class":273},"    \"roads (edited copy)\"",[232,1132,1133],{"class":241},", roads.fields(), roads.wkbType(), roads.crs())\n",[232,1135,1136,1139,1141,1144,1147,1150,1153,1155,1158],{"class":101,"line":301},[232,1137,1138],{"class":241},"request ",[232,1140,264],{"class":237},[232,1142,1143],{"class":241}," QgsFeatureRequest().setFilterExpression(",[232,1145,1146],{"class":273},"\"",[232,1148,1149],{"class":353},"\\\"",[232,1151,1152],{"class":273},"class",[232,1154,1149],{"class":353},[232,1156,1157],{"class":273}," = 'primary'\"",[232,1159,310],{"class":241},[232,1161,1162,1165,1167],{"class":101,"line":307},[232,1163,1164],{"class":241},"batch ",[232,1166,264],{"class":237},[232,1168,833],{"class":241},[232,1170,1171,1173,1176,1178],{"class":101,"line":313},[232,1172,838],{"class":237},[232,1174,1175],{"class":241}," f ",[232,1177,844],{"class":237},[232,1179,1180],{"class":241}," roads.getFeatures(request):\n",[232,1182,1183,1186,1189],{"class":101,"line":335},[232,1184,1185],{"class":241},"    f.setGeometry(f.geometry().simplify(",[232,1187,1188],{"class":353},"2.0",[232,1190,920],{"class":241},[232,1192,1193],{"class":101,"line":347},[232,1194,1195],{"class":241},"    batch.append(f)\n",[232,1197,1198],{"class":101,"line":365},[232,1199,1200],{"class":241},"copy.dataProvider().addFeatures(batch)\n",[232,1202,1203],{"class":101,"line":370},[232,1204,1205],{"class":241},"copy.updateExtents()\n",[232,1207,1208],{"class":101,"line":379},[232,1209,255],{"emptyLinePlaceholder":254},[232,1211,1212],{"class":101,"line":865},[232,1213,1214],{"class":1114},"# 2. a filled snapshot in one call\n",[232,1216,1217,1220,1222,1225,1227,1229,1231,1233,1235],{"class":101,"line":871},[232,1218,1219],{"class":241},"snapshot ",[232,1221,264],{"class":237},[232,1223,1224],{"class":241}," roads.materialize(QgsFeatureRequest().setFilterExpression(",[232,1226,1146],{"class":273},[232,1228,1149],{"class":353},[232,1230,1152],{"class":273},[232,1232,1149],{"class":353},[232,1234,1157],{"class":273},[232,1236,920],{"class":241},[232,1238,1239,1242,1245],{"class":101,"line":877},[232,1240,1241],{"class":241},"snapshot.setName(",[232,1243,1244],{"class":273},"\"primary roads (snapshot)\"",[232,1246,310],{"class":241},[232,1248,1249],{"class":101,"line":882},[232,1250,1251],{"class":241},"QgsProject.instance().addMapLayers([copy, snapshot])\n",[14,1253,1254,1256,1257,1260,1261,205,1264,1267,1268,198],{},[386,1255,388],{}," Features read from the source keep their attribute order, so they can be added to a layer with the same fields unchanged — no copying attribute by attribute. The simplify step stands for whatever modification the script needs. ",[195,1258,1259],{},"materialize"," is the shortest route when no per-feature logic is involved; it also accepts ",[195,1262,1263],{},"setSubsetOfAttributes",[195,1265,1266],{},"setDestinationCrs"," on the request, giving you a reprojected, column-trimmed copy in a single call. Both results are fully independent: editing them never touches ",[195,1269,1022],{},[183,1271,1273],{"id":1272},"keep-the-layer-alive-in-scripts-and-plugins","Keep the layer alive in scripts and plugins",[14,1275,1276],{},"A memory layer owns its features, and Python owns the layer until something else takes it over. That ownership rule explains the most confusing memory-layer bug: a layer created inside a function, returned to nothing and never added to a project, is garbage-collected when the function returns — and a layer added to the project from a plugin, then removed, takes its features with it.",[223,1278,1280],{"className":225,"code":1279,"language":227,"meta":228,"style":228},"from qgis.core import QgsVectorLayer, QgsProject\n\ndef build_scratch():\n    layer = QgsVectorLayer(\"LineString?crs=EPSG:4326&field=label:string\", \"scratch\", \"memory\")\n    # ... fill it ...\n    return layer                      # caller must keep this reference\n\nscratch = build_scratch()             # alive while `scratch` is referenced\nQgsProject.instance().addMapLayer(scratch, addToLegend=False)  # project now owns it\n\n# later: the project deletes the C++ object; the Python name becomes a dead wrapper\nQgsProject.instance().removeMapLayer(scratch.id())\ntry:\n    scratch.featureCount()\nexcept RuntimeError as err:\n    print(\"layer already deleted:\", err)\n",[195,1281,1282,1292,1296,1308,1332,1337,1348,1352,1365,1384,1388,1393,1398,1406,1411,1424],{"__ignoreMap":228},[232,1283,1284,1286,1288,1290],{"class":101,"line":234},[232,1285,238],{"class":237},[232,1287,242],{"class":241},[232,1289,245],{"class":237},[232,1291,248],{"class":241},[232,1293,1294],{"class":101,"line":251},[232,1295,255],{"emptyLinePlaceholder":254},[232,1297,1298,1301,1305],{"class":101,"line":258},[232,1299,1300],{"class":237},"def",[232,1302,1304],{"class":1303},"svObZ"," build_scratch",[232,1306,1307],{"class":241},"():\n",[232,1309,1310,1313,1315,1318,1321,1323,1326,1328,1330],{"class":101,"line":270},[232,1311,1312],{"class":241},"    layer ",[232,1314,264],{"class":237},[232,1316,1317],{"class":241}," QgsVectorLayer(",[232,1319,1320],{"class":273},"\"LineString?crs=EPSG:4326&field=label:string\"",[232,1322,327],{"class":241},[232,1324,1325],{"class":273},"\"scratch\"",[232,1327,327],{"class":241},[232,1329,330],{"class":273},[232,1331,310],{"class":241},[232,1333,1334],{"class":101,"line":277},[232,1335,1336],{"class":1114},"    # ... fill it ...\n",[232,1338,1339,1342,1345],{"class":101,"line":283},[232,1340,1341],{"class":237},"    return",[232,1343,1344],{"class":241}," layer                      ",[232,1346,1347],{"class":1114},"# caller must keep this reference\n",[232,1349,1350],{"class":101,"line":289},[232,1351,255],{"emptyLinePlaceholder":254},[232,1353,1354,1357,1359,1362],{"class":101,"line":295},[232,1355,1356],{"class":241},"scratch ",[232,1358,264],{"class":237},[232,1360,1361],{"class":241}," build_scratch()             ",[232,1363,1364],{"class":1114},"# alive while `scratch` is referenced\n",[232,1366,1367,1370,1373,1375,1378,1381],{"class":101,"line":301},[232,1368,1369],{"class":241},"QgsProject.instance().addMapLayer(scratch, ",[232,1371,1372],{"class":645},"addToLegend",[232,1374,264],{"class":237},[232,1376,1377],{"class":353},"False",[232,1379,1380],{"class":241},")  ",[232,1382,1383],{"class":1114},"# project now owns it\n",[232,1385,1386],{"class":101,"line":307},[232,1387,255],{"emptyLinePlaceholder":254},[232,1389,1390],{"class":101,"line":313},[232,1391,1392],{"class":1114},"# later: the project deletes the C++ object; the Python name becomes a dead wrapper\n",[232,1394,1395],{"class":101,"line":335},[232,1396,1397],{"class":241},"QgsProject.instance().removeMapLayer(scratch.id())\n",[232,1399,1400,1403],{"class":101,"line":347},[232,1401,1402],{"class":237},"try",[232,1404,1405],{"class":241},":\n",[232,1407,1408],{"class":101,"line":365},[232,1409,1410],{"class":241},"    scratch.featureCount()\n",[232,1412,1413,1416,1418,1421],{"class":101,"line":370},[232,1414,1415],{"class":237},"except",[232,1417,354],{"class":353},[232,1419,1420],{"class":237}," as",[232,1422,1423],{"class":241}," err:\n",[232,1425,1426,1429,1431,1434],{"class":101,"line":379},[232,1427,1428],{"class":353},"    print",[232,1430,357],{"class":241},[232,1432,1433],{"class":273},"\"layer already deleted:\"",[232,1435,1436],{"class":241},", err)\n",[14,1438,1439,925,1441,1444,1445,1448,1449,1452,1453,198],{},[386,1440,388],{},[195,1442,1443],{},"addMapLayer(layer, addToLegend=False)"," is a useful middle ground for helper layers: the project owns and keeps the layer, Processing and expressions can see it by id, but it does not clutter the Layers panel. Once the project removes a layer, the underlying C++ object is destroyed and any Python variable still pointing at it raises ",[195,1446,1447],{},"RuntimeError: wrapped C\u002FC++ object … has been deleted",". The fix is not to keep the reference longer, but to stop using the layer after removal — or to call ",[195,1450,1451],{},"scratch.clone()"," first if the data is still needed. The wider rules behind this are covered in ",[21,1454,1456],{"href":1455},"\u002Fpyqgis-fundamentals-environment-setup\u002Fqgis-api-architecture\u002Fqgis-object-ownership-and-crashes-pyqgis\u002F","object ownership and crashes",[14,1458,1459,1460,1463,1464,1467],{},"Memory layers are also handy for reading a layer's definition back. ",[195,1461,1462],{},"layer.source()"," on a memory layer returns its URI including the fields that were added later, so ",[195,1465,1466],{},"QgsVectorLayer(layer.source(), \"empty twin\", \"memory\")"," produces an empty layer with an identical schema — another quick way to clone the structure without the data.",[183,1469,1471],{"id":1470},"save-the-result-before-it-disappears","Save the result before it disappears",[14,1473,1474],{},"A memory layer is lost when QGIS closes. Recent versions warn when a project with memory layers is closed, but scripts that run headless get no warning at all. When the layer is a result rather than a scratch surface, write it out.",[223,1476,1478],{"className":225,"code":1477,"language":227,"meta":228,"style":228},"import processing\n\nout = processing.run(\"native:savefeatures\", {\n    \"INPUT\": masts,\n    \"OUTPUT\": \"\u002Fdata\u002Fresults\u002Fmasts.gpkg\",\n    \"LAYER_NAME\": \"masts\",\n})[\"OUTPUT\"]\n\nsaved = QgsVectorLayer(out, \"masts\", \"ogr\")\nprint(saved.isValid(), saved.featureCount(), \"features written\")\n\n# keep the styling: copy the renderer from the scratch layer\nsaved.setRenderer(masts.renderer().clone())\nQgsProject.instance().addMapLayer(saved)\nQgsProject.instance().removeMapLayer(masts.id())\n",[195,1479,1480,1487,1491,1507,1515,1529,1540,1550,1554,1573,1585,1589,1594,1599,1604],{"__ignoreMap":228},[232,1481,1482,1484],{"class":101,"line":234},[232,1483,245],{"class":237},[232,1485,1486],{"class":241}," processing\n",[232,1488,1489],{"class":101,"line":251},[232,1490,255],{"emptyLinePlaceholder":254},[232,1492,1493,1496,1498,1501,1504],{"class":101,"line":258},[232,1494,1495],{"class":241},"out ",[232,1497,264],{"class":237},[232,1499,1500],{"class":241}," processing.run(",[232,1502,1503],{"class":273},"\"native:savefeatures\"",[232,1505,1506],{"class":241},", {\n",[232,1508,1509,1512],{"class":101,"line":270},[232,1510,1511],{"class":273},"    \"INPUT\"",[232,1513,1514],{"class":241},": masts,\n",[232,1516,1517,1520,1523,1526],{"class":101,"line":277},[232,1518,1519],{"class":273},"    \"OUTPUT\"",[232,1521,1522],{"class":241},": ",[232,1524,1525],{"class":273},"\"\u002Fdata\u002Fresults\u002Fmasts.gpkg\"",[232,1527,1528],{"class":241},",\n",[232,1530,1531,1534,1536,1538],{"class":101,"line":283},[232,1532,1533],{"class":273},"    \"LAYER_NAME\"",[232,1535,1522],{"class":241},[232,1537,324],{"class":273},[232,1539,1528],{"class":241},[232,1541,1542,1545,1548],{"class":101,"line":289},[232,1543,1544],{"class":241},"})[",[232,1546,1547],{"class":273},"\"OUTPUT\"",[232,1549,823],{"class":241},[232,1551,1552],{"class":101,"line":295},[232,1553,255],{"emptyLinePlaceholder":254},[232,1555,1556,1559,1561,1564,1566,1568,1571],{"class":101,"line":301},[232,1557,1558],{"class":241},"saved ",[232,1560,264],{"class":237},[232,1562,1563],{"class":241}," QgsVectorLayer(out, ",[232,1565,324],{"class":273},[232,1567,327],{"class":241},[232,1569,1570],{"class":273},"\"ogr\"",[232,1572,310],{"class":241},[232,1574,1575,1577,1580,1583],{"class":101,"line":307},[232,1576,373],{"class":353},[232,1578,1579],{"class":241},"(saved.isValid(), saved.featureCount(), ",[232,1581,1582],{"class":273},"\"features written\"",[232,1584,310],{"class":241},[232,1586,1587],{"class":101,"line":313},[232,1588,255],{"emptyLinePlaceholder":254},[232,1590,1591],{"class":101,"line":335},[232,1592,1593],{"class":1114},"# keep the styling: copy the renderer from the scratch layer\n",[232,1595,1596],{"class":101,"line":347},[232,1597,1598],{"class":241},"saved.setRenderer(masts.renderer().clone())\n",[232,1600,1601],{"class":101,"line":365},[232,1602,1603],{"class":241},"QgsProject.instance().addMapLayer(saved)\n",[232,1605,1606],{"class":101,"line":370},[232,1607,1608],{"class":241},"QgsProject.instance().removeMapLayer(masts.id())\n",[14,1610,1611,925,1613,1616,1617,1619,1620,1623,1624,1628],{},[386,1612,388],{},[195,1614,1615],{},"native:savefeatures"," writes any vector layer to any OGR format and returns the path with the layer name appended, ready to pass back to ",[195,1618,204],{},". Swapping the memory layer for the saved one, with the renderer cloned across, means the map looks the same but now survives a restart. Recent QGIS versions can also store memory layer features inside the ",[195,1621,1622],{},".qgz"," when a project is ",[21,1625,1627],{"href":1626},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002Fsave-and-load-qgis-project-pyqgis\u002F","saved from Python",", which suits interactive work; for automation, an explicit GeoPackage is clearer and readable by any other tool.",[183,1630,1632],{"id":1631},"qgis-version-compatibility","QGIS version compatibility",[14,1634,1635,1636,1639,1640,1643,1644,1646,1647,1650,1651,1654,1655,327,1657,327,1660,1663,1664,1667,1668,1671],{},"The memory provider and its URI syntax are stable across all QGIS 3 releases and QGIS 4. ",[195,1637,1638],{},"QgsMemoryProviderUtils.createMemoryLayer"," has existed since 3.0; ",[195,1641,1642],{},"QgsVectorLayer.materialize"," since 3.0 as well. The ",[195,1645,435],{}," field type and list types need 3.28 or newer. The one breaking change is in field types for Qt6-based QGIS 4 builds, where ",[195,1648,1649],{},"QgsField"," takes ",[195,1652,1653],{},"QMetaType.Type"," values (",[195,1656,952],{},[195,1658,1659],{},"QMetaType.Type.Double",[195,1661,1662],{},"QMetaType.Type.Int",") rather than ",[195,1665,1666],{},"QVariant"," constants; QGIS 3.38 and later accept both, so writing the ",[195,1669,1670],{},"QMetaType"," form today keeps a script portable.",[183,1673,1675],{"id":1674},"troubleshooting","Troubleshooting",[188,1677,1678,1687,1699,1717],{},[191,1679,1680,1683,1684,1686],{},[386,1681,1682],{},"The layer is valid but shows nothing."," The CRS was omitted, so coordinates in metres are being drawn as degrees somewhere off the map; or ",[195,1685,948],{}," was never called.",[191,1688,1689,1692,1693,1696,1697,198],{},[386,1690,1691],{},"Attributes are all NULL."," The feature was created with ",[195,1694,1695],{},"QgsFeature()"," and no fields, or with fields fetched before ",[195,1698,928],{},[191,1700,1701,1706,1707,1710,1711,1713,1714,1716],{},[386,1702,1703,1705],{},[195,1704,944],{}," returns False."," A feature carries more attributes than the layer has fields, or a geometry of the wrong type — a ",[195,1708,1709],{},"MultiPolygon"," into a ",[195,1712,398],{}," layer. Create the layer as the ",[195,1715,402],{}," type to accept both.",[191,1718,1719,1722],{},[386,1720,1721],{},"The layer vanished after reopening the project."," Memory layers are not stored unless saved; write them out as shown above.",[183,1724,1726],{"id":1725},"conclusion","Conclusion",[14,1728,1729,1730,417,1733,1735,1736,1738],{},"Declare a memory layer completely in its URI — geometry type, CRS, fields and index — add features in batches through the provider, use ",[195,1731,1732],{},"createMemoryLayer",[195,1734,1259],{}," to copy an existing schema, and save anything worth keeping with ",[195,1737,1615],{}," before the session ends.",[183,1740,1742],{"id":1741},"frequently-asked-questions","Frequently Asked Questions",[14,1744,1745,1748],{},[386,1746,1747],{},"Are memory layers faster than GeoPackage for intermediate results?","\nUsually yes for small and medium layers, because there is no disk I\u002FO. For millions of features the RAM cost becomes the limit, and a temporary GeoPackage is the safer choice.",[14,1750,1751,1754,1755,417,1758,1761,1762,198],{},[386,1752,1753],{},"Can Processing algorithms write to a memory layer?","\nYes — pass ",[195,1756,1757],{},"\"OUTPUT\": \"memory:\"",[195,1759,1760],{},"QgsProcessing.TEMPORARY_OUTPUT",", as covered in ",[21,1763,1765],{"href":1764},"\u002Fspatial-data-processing-automation\u002Fchaining-processing-algorithms\u002Fuse-memory-layers-between-algorithms-pyqgis\u002F","using memory layers between algorithms",[14,1767,1768,1771,1772,1774,1775,198],{},[386,1769,1770],{},"How do I make an attribute-only table?","\nUse ",[195,1773,424],{}," as the geometry type: ",[195,1776,1777],{},"QgsVectorLayer(\"None?field=code:string\", \"lookup\", \"memory\")",[14,1779,1780,1783,1784,327,1787,417,1790,1793],{},[386,1781,1782],{},"Does a memory layer support curved geometries?","\nYes. Use ",[195,1785,1786],{},"CompoundCurve",[195,1788,1789],{},"CurvePolygon",[195,1791,1792],{},"MultiSurface"," as the geometry type.",[183,1795,1797],{"id":1796},"related","Related",[188,1799,1800,1805,1810,1816,1821],{},[191,1801,1802,1804],{},[21,1803,24],{"href":23}," — the guide this recipe belongs to",[191,1806,1807],{},[21,1808,1809],{"href":212},"Add Features to a Vector Layer in PyQGIS",[191,1811,1812],{},[21,1813,1815],{"href":1814},"\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fcreate-geometry-from-wkt-and-geojson-pyqgis\u002F","Create Geometry from WKT and GeoJSON in PyQGIS",[191,1817,1818],{},[21,1819,1820],{"href":1764},"Use Memory Layers Between Processing Algorithms",[191,1822,1823],{},[21,1824,1826],{"href":1825},"\u002Fspatial-data-processing-automation\u002Fpostgis-and-database-workflows\u002Fwrite-vector-layer-to-geopackage-pyqgis\u002F","Write a Vector Layer to GeoPackage in PyQGIS",[1828,1829,1830],"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 .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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);}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":228,"searchDepth":251,"depth":251,"links":1832},[1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843],{"id":185,"depth":251,"text":186},{"id":217,"depth":251,"text":218},{"id":585,"depth":251,"text":586},{"id":977,"depth":251,"text":978},{"id":1272,"depth":251,"text":1273},{"id":1470,"depth":251,"text":1471},{"id":1631,"depth":251,"text":1632},{"id":1674,"depth":251,"text":1675},{"id":1725,"depth":251,"text":1726},{"id":1741,"depth":251,"text":1742},{"id":1796,"depth":251,"text":1797},"Build temporary in-memory vector layers from Python — the URI that declares geometry type, CRS and fields, adding features in bulk, cloning an existing layer's schema, and saving the result to GeoPackage before QGIS closes.","md",{"slug":1847,"type":1848,"breadcrumb":1849,"datePublished":1850,"dateModified":1850},"create-memory-layer-pyqgis","article","Create a Memory Layer","2026-10-02","\u002Fpyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fcreate-memory-layer-pyqgis",{"title":5,"description":1844},"pyqgis-fundamentals-environment-setup\u002Ffeatures-geometries-and-memory-layers\u002Fcreate-memory-layer-pyqgis\u002Findex","-xbCuzElSmCzz98Bq-DAvI_2aRL8oQ5VktiXahIvfug",1790966252924]