
Qgis Core Data Providers
- 8 installs
- 29 repo stars
- Updated July 8, 2026
- openaec-foundation/qgis-claude-skill-package
Helps with ai & agent building tasks.
About
qgis-core-data-providers is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- qgis-core-data-providers
- AI & Agent Building
- AI-coding skill
Qgis Core Data Providers by the numbers
- 8 all-time installs (skills.sh)
- Ranked #12,339 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/qgis-claude-skill-package --skill qgis-core-data-providersAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 29 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/qgis-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
qgis-core-data-providers
Quick Reference
Provider System Overview
QGIS uses a plugin-based provider architecture. Providers are registered in QgsProviderRegistry and loaded during QgsApplication.initQgis(). Each provider handles one or more data formats.
| Provider Key | Type | Formats |
|---|---|---|
"ogr" | Vector | Shapefile, GeoPackage, GeoJSON, FlatGeoBuf, KML, DXF, GPX |
"postgres" | Vector | PostGIS tables and views |
"spatialite" | Vector | SpatiaLite databases |
"memory" | Vector | In-memory temporary layers |
"delimitedtext" | Vector | CSV, TSV, custom-delimited text files |
"WFS" | Vector | OGC Web Feature Service |
"virtual" | Vector | SQL queries across loaded layers |
"gdal" | Raster | GeoTIFF, JPEG2000, COG, VRT, GeoPackage raster |
"wms" | Raster | WMS, WMTS, XYZ tiles |
"wcs" | Raster | OGC Web Coverage Service |
"postgresraster" | Raster | PostGIS raster tables |
"pdal" | Point Cloud | LAS, LAZ (QGIS 3.18+) |
"copc" | Point Cloud | Cloud Optimized Point Cloud (QGIS 3.26+) |
"ept" | Point Cloud | Entwine Point Tile (QGIS 3.18+) |
"mdal" | Mesh | NetCDF, GRIB, XMDF, DAT |
"vectortile" | Vector Tile | Mapbox Vector Tiles (MVT) |
"cesiumtiles" | Tiled Scene | Cesium 3D Tiles (QGIS 3.34+) |
Layer Construction Pattern
# Vector layer
vlayer = QgsVectorLayer(data_source_uri, display_name, provider_key)
# Raster layer
rlayer = QgsRasterLayer(data_source_uri, display_name, provider_key)
# Point cloud layer (QGIS 3.18+)
pclayer = QgsPointCloudLayer(data_source_uri, display_name, provider_key)
# Mesh layer
mlayer = QgsMeshLayer(data_source_uri, display_name, provider_key)
# Vector tile layer
vtlayer = QgsVectorTileLayer(data_source_uri, display_name)ALWAYS check validity immediately after creation:
layer = QgsVectorLayer(uri, name, provider)
if not layer.isValid():
raise RuntimeError(f"Failed to load layer '{name}' from: {uri}")---
Critical Warnings
NEVER skip isValid() after layer creation. A layer object is ALWAYS returned even when loading fails -- the constructor NEVER raises exceptions.
NEVER use backslashes in URIs, even on Windows. QGIS/Qt normalizes to forward slashes internally. Backslashes in URIs cause silent provider failures.
NEVER pass True to uri.uri(expandAuthConfig) when logging or displaying URIs. This exposes authentication credentials in plain text. ALWAYS use uri.uri(False).
NEVER assume a GeoPackage contains a single layer. ALWAYS use explicit |layername= in the URI or enumerate sublayers first.
ALWAYS call layer.updateExtents() after adding features to a memory layer. Without this, zoom-to-layer returns a wrong extent.
ALWAYS call layer.updateFields() after calling dataProvider().addAttributes(). Without this, the layer schema is stale.
ALWAYS use file:/// prefix (three slashes) for delimited text URIs with absolute paths.
NEVER access features or data provider methods on an invalid layer -- this causes crashes or undefined behavior.
---
Decision Tree: Which Format to Use
Need to store spatial data?
├── Temporary / in-memory only?
│ └── USE: memory provider
├── Exchange with non-GIS tools?
│ ├── JSON-based → USE: GeoJSON
│ └── Tabular → USE: CSV with delimitedtext provider
├── Single-layer vector file?
│ ├── Small dataset → USE: GeoPackage (single layer)
│ └── Streaming / append-heavy → USE: FlatGeoBuf
├── Multi-layer project database?
│ └── USE: GeoPackage (recommended default)
├── Enterprise / multi-user database?
│ └── USE: PostGIS with postgres provider
├── Web service?
│ ├── Vector features → USE: WFS
│ ├── Map images → USE: WMS
│ ├── Tile basemaps → USE: XYZ tiles via wms provider
│ └── Raw raster coverage → USE: WCS
├── Raster data?
│ ├── Local file → USE: GeoTIFF via gdal provider
│ ├── Cloud storage → USE: COG via /vsicurl/
│ └── Database → USE: postgresraster
├── Point cloud / LiDAR?
│ ├── Local file → USE: pdal (LAS/LAZ)
│ └── Cloud optimized → USE: copc
└── Legacy requirement?
└── Shapefile ONLY if mandated by external systemGeoPackage is the recommended default format. It supports vector, raster, and attribute tables in a single SQLite-based file with no file count limitations (unlike Shapefile's multi-file structure).
---
Essential Patterns
Pattern 1: Load a GeoPackage Layer
from qgis.core import QgsVectorLayer, QgsProject
# Single known layer
vlayer = QgsVectorLayer("data/project.gpkg|layername=buildings", "Buildings", "ogr")
if not vlayer.isValid():
raise RuntimeError("Layer failed to load")
QgsProject.instance().addMapLayer(vlayer)Pattern 2: Enumerate All Sublayers
from qgis.core import QgsDataProvider, QgsVectorLayer, QgsProject
gpkg_path = "data/project.gpkg"
layer = QgsVectorLayer(gpkg_path, "probe", "ogr")
for sub in layer.dataProvider().subLayers():
name = sub.split(QgsDataProvider.SUBLAYER_SEPARATOR)[1]
uri = f"{gpkg_path}|layername={name}"
sub_layer = QgsVectorLayer(uri, name, "ogr")
if sub_layer.isValid():
QgsProject.instance().addMapLayer(sub_layer)Pattern 3: PostGIS Connection with QgsDataSourceUri
from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setConnection("localhost", "5432", "mydb", "user", "password")
uri.setDataSource("public", "roads", "geom", "status = 'active'", "gid")
vlayer = QgsVectorLayer(uri.uri(False), "Active Roads", "postgres")
if not vlayer.isValid():
raise RuntimeError("PostGIS connection failed")Pattern 4: Create a Memory Layer with Fields
from qgis.core import QgsVectorLayer, QgsField, QgsFeature, QgsGeometry, QgsPointXY
from qgis.PyQt.QtCore import QVariant
# URI with inline field definitions
layer = QgsVectorLayer(
"Point?crs=EPSG:4326&field=name:string(100)&field=value:double",
"Results",
"memory"
)
# OR add fields programmatically
layer = QgsVectorLayer("Point?crs=EPSG:4326", "Results", "memory")
pr = layer.dataProvider()
pr.addAttributes([
QgsField("name", QVariant.String),
QgsField("value", QVariant.Double),
])
layer.updateFields()
# Add features
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0)))
feat.setAttributes(["Sample", 42.0])
pr.addFeatures([feat])
layer.updateExtents()Pattern 5: Load WMS / XYZ Tiles
from qgis.core import QgsRasterLayer, QgsProject
# WMS
wms_uri = (
"crs=EPSG:4326"
"&format=image/png"
"&layers=my_layer"
"&styles"
"&url=https://example.com/wms"
)
wms_layer = QgsRasterLayer(wms_uri, "WMS Layer", "wms")
# XYZ tiles -- {z}/{x}/{y} MUST be URL-encoded
xyz_uri = (
"type=xyz"
"&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png"
"&zmin=0&zmax=19"
"&crs=EPSG3857"
)
xyz_layer = QgsRasterLayer(xyz_uri, "OpenStreetMap", "wms")
for lyr in [wms_layer, xyz_layer]:
if not lyr.isValid():
raise RuntimeError(f"Layer '{lyr.name()}' failed to load")
QgsProject.instance().addMapLayer(lyr)Pattern 6: Load CSV with Coordinates
import os
from qgis.core import QgsVectorLayer
csv_path = os.path.abspath("data/stations.csv").replace("\\", "/")
uri = (
f"file:///{csv_path}"
"?delimiter=,"
"&xField=longitude"
"&yField=latitude"
"&crs=EPSG:4326"
)
vlayer = QgsVectorLayer(uri, "Stations", "delimitedtext")---
Common Operations
List Available Providers
from qgis.core import QgsProviderRegistry
registry = QgsProviderRegistry.instance()
for key in registry.providerList():
print(key)Load Raster from GeoPackage
from qgis.core import QgsRasterLayer
rlayer = QgsRasterLayer("GPKG:/data/rasters.gpkg:elevation", "Elevation", "gdal")Load Cloud Optimized GeoTIFF (COG)
from qgis.core import QgsRasterLayer
rlayer = QgsRasterLayer("/vsicurl/https://example.com/data.tif", "Remote COG", "gdal")Load WFS Layer
from qgis.core import QgsVectorLayer
uri = "https://example.com/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=ns:layer"
vlayer = QgsVectorLayer(uri, "WFS Layer", "WFS")Load SpatiaLite Layer
from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setDatabase("/data/regions.sqlite")
uri.setDataSource("", "regions", "geometry")
vlayer = QgsVectorLayer(uri.uri(), "Regions", "spatialite")Virtual Layer (SQL Across Loaded Layers)
from qgis.core import QgsVectorLayer
uri = "?query=SELECT * FROM airports WHERE elevation > 500"
vlayer = QgsVectorLayer(uri, "High Airports", "virtual")Materialize Selection as Memory Layer
from qgis.core import QgsFeatureRequest, QgsProject
memory_layer = source_layer.materialize(
QgsFeatureRequest().setFilterFids(source_layer.selectedFeatureIds())
)
QgsProject.instance().addMapLayer(memory_layer)---
Reference Links
- references/methods.md -- API signatures for QgsDataSourceUri, QgsVectorLayer, QgsRasterLayer, QgsProviderRegistry
- references/examples.md -- URI format strings for every supported provider
- references/anti-patterns.md -- What NOT to do when loading data
Official Sources
- https://qgis.org/pyqgis/master/core/QgsVectorLayer.html
- https://qgis.org/pyqgis/master/core/QgsRasterLayer.html
- https://qgis.org/pyqgis/master/core/QgsDataSourceUri.html
- https://qgis.org/pyqgis/master/core/QgsProviderRegistry.html
- https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/loadlayer.html
qgis-core-data-providers — Anti-Patterns
AP-001: Skipping Layer Validity Check
WRONG:
layer = QgsVectorLayer("data/roads.gpkg|layername=roads", "Roads", "ogr")
QgsProject.instance().addMapLayer(layer) # May add invalid layer silently
for feat in layer.getFeatures(): # Crashes or undefined behavior on invalid layer
print(feat)CORRECT:
layer = QgsVectorLayer("data/roads.gpkg|layername=roads", "Roads", "ogr")
if not layer.isValid():
raise RuntimeError(f"Failed to load layer: {layer.error().summary()}")
QgsProject.instance().addMapLayer(layer)Why: QgsVectorLayer() and QgsRasterLayer() NEVER raise exceptions on failure. They ALWAYS return a layer object. The ONLY way to detect failure is isValid(). Accessing features on an invalid layer causes crashes.
---
AP-002: Using Backslashes in URIs on Windows
WRONG:
layer = QgsVectorLayer("C:\\Users\\data\\file.gpkg|layername=roads", "Roads", "ogr")CORRECT:
layer = QgsVectorLayer("C:/Users/data/file.gpkg|layername=roads", "Roads", "ogr")
# OR use os.path and replace:
import os
path = os.path.join("C:\\Users", "data", "file.gpkg").replace("\\", "/")
layer = QgsVectorLayer(f"{path}|layername=roads", "Roads", "ogr")Why: QGIS/Qt normalizes paths to forward slashes internally. Backslashes in URI strings cause provider parsing failures that result in silent load failures (layer is invalid with no clear error).
---
AP-003: Assuming GeoPackage Has Only One Layer
WRONG:
layer = QgsVectorLayer("data/project.gpkg", "Data", "ogr")
# Loads the first layer by default — but WHICH first layer is undefinedCORRECT:
layer = QgsVectorLayer("data/project.gpkg|layername=buildings", "Buildings", "ogr")Why: A GeoPackage can contain multiple vector layers, raster layers, and attribute tables. Without |layername=, the provider picks the first layer it encounters, which may not be the intended one. The ordering is not guaranteed across QGIS versions.
---
AP-004: Exposing Credentials via uri.uri(True)
WRONG:
uri = QgsDataSourceUri()
uri.setConnection("db.example.com", "5432", "gisdb", "admin", "s3cr3t_passw0rd")
uri.setDataSource("public", "roads", "geom")
print(f"Loading from: {uri.uri(True)}") # Prints credentials in plain text
logger.info(f"Connection URI: {uri.uri(True)}") # Credentials in log filesCORRECT:
print(f"Loading from: {uri.uri(False)}") # Credentials are hidden
logger.info(f"Connection URI: {uri.uri(False)}")Why: uri.uri(True) expands authentication configurations and includes the raw username/password in the returned string. This leaks credentials to log files, console output, and error messages. ALWAYS use uri.uri(False) for any display or logging purpose.
---
AP-005: Forgetting updateExtents() on Memory Layers
WRONG:
layer = QgsVectorLayer("Point?crs=EPSG:4326", "Points", "memory")
pr = layer.dataProvider()
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0)))
pr.addFeatures([feat])
QgsProject.instance().addMapLayer(layer)
# Zoom to layer shows wrong extent (empty or 0,0)CORRECT:
layer = QgsVectorLayer("Point?crs=EPSG:4326", "Points", "memory")
pr = layer.dataProvider()
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(5.0, 52.0)))
pr.addFeatures([feat])
layer.updateExtents() # REQUIRED after adding features
QgsProject.instance().addMapLayer(layer)Why: Memory layers do not automatically recalculate their spatial extent when features are added via the data provider. Without updateExtents(), the layer reports a zero or stale extent, causing "Zoom to Layer" to fail.
---
AP-006: Forgetting updateFields() After Adding Attributes
WRONG:
layer = QgsVectorLayer("Point?crs=EPSG:4326", "Points", "memory")
pr = layer.dataProvider()
pr.addAttributes([QgsField("name", QVariant.String)])
# layer.fields() still returns the old field list
feat = QgsFeature(layer.fields()) # Feature has wrong field countCORRECT:
layer = QgsVectorLayer("Point?crs=EPSG:4326", "Points", "memory")
pr = layer.dataProvider()
pr.addAttributes([QgsField("name", QVariant.String)])
layer.updateFields() # REQUIRED to sync layer schema
feat = QgsFeature(layer.fields())Why: addAttributes() modifies the data provider's schema but does NOT automatically update the QgsVectorLayer's cached field list. Without updateFields(), layer.fields() returns stale data and features created from it have the wrong number of fields.
---
AP-007: Missing file:// Prefix for Delimited Text
WRONG:
uri = "/data/stations.csv?delimiter=,&xField=lon&yField=lat"
vlayer = QgsVectorLayer(uri, "Stations", "delimitedtext")
# Layer is invalid — delimitedtext provider requires file:// prefixCORRECT:
uri = "file:///data/stations.csv?delimiter=,&xField=lon&yField=lat&crs=EPSG:4326"
vlayer = QgsVectorLayer(uri, "Stations", "delimitedtext")Why: The delimited text provider ALWAYS requires the file:// URI scheme prefix. For absolute paths, use three slashes (file:///). Omitting it causes the provider to fail silently.
---
AP-008: Using Wrong Case for WFS Provider Key
WRONG:
vlayer = QgsVectorLayer(wfs_url, "WFS Layer", "wfs") # lowercase — WRONGCORRECT:
vlayer = QgsVectorLayer(wfs_url, "WFS Layer", "WFS") # uppercase — CORRECTWhy: The WFS provider key is "WFS" (uppercase), unlike most other provider keys which are lowercase. Using "wfs" causes a provider-not-found error. This is a common source of confusion.
---
AP-009: Not URL-Encoding XYZ Tile Placeholders
WRONG:
uri = "type=xyz&url=https://tile.openstreetmap.org/{z}/{x}/{y}.png&zmin=0&zmax=19"
rlayer = QgsRasterLayer(uri, "OSM", "wms")
# Fails because {z}, {x}, {y} are not URL-encodedCORRECT:
uri = "type=xyz&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmin=0&zmax=19&crs=EPSG3857"
rlayer = QgsRasterLayer(uri, "OSM", "wms")Why: The {z}, {x}, {y} placeholders in XYZ tile URLs MUST be URL-encoded as %7Bz%7D, %7Bx%7D, %7By%7D when used in the URI string. The curly braces are interpreted as URI delimiters if not encoded, causing the provider to fail.
---
AP-010: Hardcoding Absolute Paths in Cross-Platform Code
WRONG:
layer = QgsVectorLayer("/home/user/data/roads.gpkg|layername=roads", "Roads", "ogr")CORRECT:
import os
data_dir = os.path.join(QgsProject.instance().homePath(), "data")
layer_path = os.path.join(data_dir, "roads.gpkg").replace("\\", "/")
layer = QgsVectorLayer(f"{layer_path}|layername=roads", "Roads", "ogr")Why: Hardcoded absolute paths break when the project is moved to another machine or operating system. ALWAYS construct paths relative to the project directory using QgsProject.instance().homePath() or use os.path.join().
---
AP-011: Creating Layers on Background Threads
WRONG:
import threading
def load_data():
layer = QgsVectorLayer("data.gpkg|layername=roads", "Roads", "ogr")
QgsProject.instance().addMapLayer(layer) # NOT thread-safe
thread = threading.Thread(target=load_data)
thread.start()CORRECT:
from qgis.core import QgsTask, QgsApplication
class LoadTask(QgsTask):
def run(self):
# Do heavy processing here (reading, transforming)
self.result_data = process_data()
return True
def finished(self, result):
# This runs on the main thread — safe to add layers
if result:
layer = QgsVectorLayer(...)
QgsProject.instance().addMapLayer(layer)
task = LoadTask("Load Data")
QgsApplication.taskManager().addTask(task)Why: QgsProject.instance() is NOT thread-safe for writes. Creating layers and adding them to the project from background threads causes race conditions, crashes, and data corruption. ALWAYS use QgsTask and add layers in the finished() callback, which runs on the main thread.
---
AP-012: Omitting Provider Key for Non-Default Providers
WRONG:
# Raster — provider defaults to "gdal", but WMS needs explicit provider
rlayer = QgsRasterLayer(wms_uri, "WMS Layer") # Uses "gdal" provider — failsCORRECT:
rlayer = QgsRasterLayer(wms_uri, "WMS Layer", "wms") # Explicit providerWhy: QgsRasterLayer defaults to the "gdal" provider when no provider key is given. For WMS, WMTS, XYZ, WCS, or PostGIS raster sources, you MUST specify the provider key explicitly. The GDAL provider cannot parse WMS URIs and the layer silently fails.
qgis-core-data-providers — URI Format Examples
Vector Providers
OGR Provider ("ogr")
Shapefile
vlayer = QgsVectorLayer("/data/airports.shp", "Airports", "ogr")GeoPackage (by layer name — ALWAYS preferred)
vlayer = QgsVectorLayer("/data/project.gpkg|layername=buildings", "Buildings", "ogr")GeoPackage (by layer index — AVOID, index can change)
vlayer = QgsVectorLayer("/data/project.gpkg|layerid=0", "First Layer", "ogr")GeoJSON
vlayer = QgsVectorLayer("/data/boundaries.geojson", "Boundaries", "ogr")FlatGeoBuf
vlayer = QgsVectorLayer("/data/parcels.fgb", "Parcels", "ogr")KML
vlayer = QgsVectorLayer("/data/places.kml", "Places", "ogr")DXF (with geometry type filter)
vlayer = QgsVectorLayer(
"/data/drawing.dxf|layername=entities|geometrytype=Polygon",
"DXF Polygons",
"ogr"
)DXF geometrytype values: Point, LineString, Polygon.
GPX
vlayer = QgsVectorLayer("/data/track.gpx?type=track", "GPS Track", "gpx")GPX type values: track, route, waypoint.
MySQL via OGR
vlayer = QgsVectorLayer(
"MySQL:mydb,host=localhost,port=3306,user=root,password=xxx|layername=my_table",
"MySQL Table",
"ogr"
)Enumerate All GeoPackage Sublayers
from qgis.core import QgsDataProvider, QgsVectorLayer, QgsProject
gpkg_path = "/data/multi_layer.gpkg"
probe = QgsVectorLayer(gpkg_path, "probe", "ogr")
for sub in probe.dataProvider().subLayers():
name = sub.split(QgsDataProvider.SUBLAYER_SEPARATOR)[1]
uri = f"{gpkg_path}|layername={name}"
layer = QgsVectorLayer(uri, name, "ogr")
if layer.isValid():
QgsProject.instance().addMapLayer(layer)---
PostGIS Provider ("postgres")
Basic Connection
from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setConnection("localhost", "5432", "gisdb", "user", "password")
uri.setDataSource("public", "roads", "geom")
vlayer = QgsVectorLayer(uri.uri(False), "Roads", "postgres")With SQL Filter and Primary Key
uri = QgsDataSourceUri()
uri.setConnection("db.example.com", "5432", "gisdb", "analyst", "secret")
uri.setDataSource("public", "parcels", "the_geom", "area_sqm > 1000", "gid")
vlayer = QgsVectorLayer(uri.uri(False), "Large Parcels", "postgres")With SSL
uri = QgsDataSourceUri()
uri.setConnection("db.example.com", "5432", "gisdb", "user", "pass",
QgsDataSourceUri.SslRequire)
uri.setDataSource("public", "buildings", "geom")
vlayer = QgsVectorLayer(uri.uri(False), "Buildings", "postgres")With QGIS Authentication Manager
uri = QgsDataSourceUri()
uri.setConnection("db.example.com", "5432", "gisdb", "", "")
uri.setAuthConfigId("my_auth_config_id")
uri.setDataSource("public", "roads", "geom")
vlayer = QgsVectorLayer(uri.uri(False), "Roads", "postgres")---
SpatiaLite Provider ("spatialite")
from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setDatabase("/data/regions.sqlite")
uri.setDataSource("", "towns", "geometry")
vlayer = QgsVectorLayer(uri.uri(), "Towns", "spatialite")---
Memory Provider ("memory")
Geometry Types
"Point?crs=EPSG:4326"
"LineString?crs=EPSG:28992"
"Polygon?crs=EPSG:3857"
"MultiPoint?crs=EPSG:4326"
"MultiLineString?crs=EPSG:4326"
"MultiPolygon?crs=EPSG:4326"
"None" # Attribute-only table (no geometry)With Inline Field Definitions
uri = "Point?crs=EPSG:4326&field=name:string(100)&field=value:double&field=count:integer"
vlayer = QgsVectorLayer(uri, "Points", "memory")Field type keywords: string, integer, double, date, datetime, boolean.
Materialize a Selection
from qgis.core import QgsFeatureRequest
memory_layer = source_layer.materialize(
QgsFeatureRequest().setFilterFids(source_layer.selectedFeatureIds())
)---
Delimited Text Provider ("delimitedtext")
CSV with X/Y Coordinate Columns
import os
from qgis.core import QgsVectorLayer
path = os.path.abspath("data/stations.csv").replace("\\", "/")
uri = f"file:///{path}?delimiter=,&xField=longitude&yField=latitude&crs=EPSG:4326"
vlayer = QgsVectorLayer(uri, "Stations", "delimitedtext")TSV (Tab-Separated)
uri = f"file:///{path}?delimiter=\\t&xField=x&yField=y&crs=EPSG:28992"
vlayer = QgsVectorLayer(uri, "Measurements", "delimitedtext")CSV with WKT Geometry Column
uri = f"file:///{path}?delimiter=,&wktField=geom&crs=EPSG:4326&geomType=polygon"
vlayer = QgsVectorLayer(uri, "Polygons", "delimitedtext")CSV without Geometry (Attribute Table Only)
uri = f"file:///{path}?delimiter=,&geomType=none"
vlayer = QgsVectorLayer(uri, "Lookup Table", "delimitedtext")URI parameters reference:
file:///— prefix + absolute path (three slashes for absolute paths)delimiter— field separator:,,;,\txField/yField— column names for coordinateswktField— alternative: column name containing WKT geometrycrs— CRS identifier (e.g.,EPSG:4326)geomType— geometry type hint:point,line,polygon,none
---
WFS Provider ("WFS")
Note: The provider key is "WFS" (uppercase). This differs from most other provider keys.
uri = "https://example.com/wfs?service=WFS&version=2.0.0&request=GetFeature&typename=ns:cities"
vlayer = QgsVectorLayer(uri, "Cities", "WFS")With Bounding Box Filter
uri = (
"https://example.com/wfs?service=WFS&version=2.0.0"
"&request=GetFeature&typename=ns:buildings"
"&bbox=5.0,52.0,6.0,53.0,EPSG:4326"
)
vlayer = QgsVectorLayer(uri, "Buildings", "WFS")---
Virtual Layer Provider ("virtual")
# Query across layers loaded in the current project
uri = "?query=SELECT * FROM airports WHERE elevation > 500"
vlayer = QgsVectorLayer(uri, "High Airports", "virtual")
# Join two layers
uri = "?query=SELECT a.*, b.population FROM cities a JOIN stats b ON a.id = b.city_id"
vlayer = QgsVectorLayer(uri, "Cities with Stats", "virtual")---
Raster Providers
GDAL Provider ("gdal")
GeoTIFF
rlayer = QgsRasterLayer("/data/srtm.tif", "Elevation", "gdal")GeoPackage Raster
rlayer = QgsRasterLayer("GPKG:/data/rasters.gpkg:elevation", "Elevation", "gdal")Cloud Optimized GeoTIFF (COG) via /vsicurl/
rlayer = QgsRasterLayer(
"/vsicurl/https://example.com/data/cog.tif",
"Remote COG",
"gdal"
)JPEG2000
rlayer = QgsRasterLayer("/data/ortho.jp2", "Orthophoto", "gdal")Virtual Raster (VRT)
rlayer = QgsRasterLayer("/data/mosaic.vrt", "Mosaic", "gdal")---
WMS / WMTS / XYZ Provider ("wms")
Note: The "wms" provider key handles WMS, WMTS, AND XYZ tile sources.
WMS
uri = (
"crs=EPSG:4326"
"&format=image/png"
"&layers=boundaries"
"&styles"
"&url=https://example.com/wms"
)
rlayer = QgsRasterLayer(uri, "WMS Boundaries", "wms")WMS URI parameters:
url— WMS service endpoint URLlayers— comma-separated layer namesstyles— comma-separated style names (can be empty)crs— CRS identifierformat— image format (image/png,image/jpeg)username/password— optional authentication
WMTS
uri = (
"crs=EPSG:3857"
"&format=image/png"
"&layers=topographic"
"&styles=default"
"&tileMatrixSet=GoogleMapsCompatible"
"&url=https://example.com/wmts?service=WMTS&request=GetCapabilities"
)
rlayer = QgsRasterLayer(uri, "WMTS Topo", "wms")XYZ Tiles
# {z}, {x}, {y} MUST be URL-encoded as %7Bz%7D, %7Bx%7D, %7By%7D
uri = (
"type=xyz"
"&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png"
"&zmin=0&zmax=19"
"&crs=EPSG3857"
)
rlayer = QgsRasterLayer(uri, "OpenStreetMap", "wms")Common XYZ tile sources:
# OpenStreetMap
"type=xyz&url=https://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmin=0&zmax=19&crs=EPSG3857"
# Esri World Imagery
"type=xyz&url=https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/%7Bz%7D/%7By%7D/%7Bx%7D&zmin=0&zmax=18&crs=EPSG3857"---
WCS Provider ("wcs")
uri = "https://example.com/wcs?identifier=dem_layer"
rlayer = QgsRasterLayer(uri, "DEM Coverage", "wcs")WCS URI parameters: url, identifier, time, format, crs, username, password, cache.
---
PostGIS Raster Provider ("postgresraster")
from qgis.core import QgsDataSourceUri, QgsRasterLayer
uri = QgsDataSourceUri()
uri.setConnection("localhost", "5432", "gisdb", "user", "password")
uri.setDataSource("public", "elevation_raster", "rast")
rlayer = QgsRasterLayer(uri.uri(False), "Elevation", "postgresraster")---
Point Cloud Providers (QGIS 3.18+)
PDAL Provider ("pdal")
from qgis.core import QgsPointCloudLayer
pclayer = QgsPointCloudLayer("/data/lidar.las", "LiDAR", "pdal")
# Also supports: .laz (compressed)COPC Provider ("copc") — QGIS 3.26+
pclayer = QgsPointCloudLayer("/data/cloud.copc.laz", "COPC Cloud", "copc")EPT Provider ("ept")
pclayer = QgsPointCloudLayer("/data/ept/ept.json", "EPT Cloud", "ept")---
Mesh Provider
MDAL Provider ("mdal")
from qgis.core import QgsMeshLayer
mlayer = QgsMeshLayer("/data/flow.nc", "Flow Model", "mdal")
# Supports: NetCDF, GRIB, XMDF, DAT, and other mesh formats---
Vector Tile Provider
Mapbox Vector Tiles
from qgis.core import QgsVectorTileLayer
uri = "type=xyz&url=https://example.com/tiles/{z}/{x}/{y}.pbf&zmin=0&zmax=14"
vtlayer = QgsVectorTileLayer(uri, "Vector Tiles")---
3D Tiled Scene Provider (QGIS 3.34+)
Cesium 3D Tiles
from qgis.core import QgsTiledSceneLayer
layer = QgsTiledSceneLayer("url=https://example.com/tileset.json", "3D Buildings", "cesiumtiles")qgis-core-data-providers — Method Reference
QgsVectorLayer Constructor
QgsVectorLayer(
path: str = "", # Data source URI (format depends on provider)
baseName: str = "", # Display name in layer tree
providerLib: str = "", # Provider key: "ogr", "postgres", "memory", etc.
options: QgsVectorLayer.LayerOptions = QgsVectorLayer.LayerOptions()
)Returns a QgsVectorLayer instance. ALWAYS check isValid() after construction.
LayerOptions
options = QgsVectorLayer.LayerOptions()
options.loadDefaultStyle = False # Skip loading default .qml style
options.readExtentFromXml = True # Read extent from project XML instead of scanning data---
QgsRasterLayer Constructor
QgsRasterLayer(
uri: str = "", # Data source URI
baseName: str = "", # Display name in layer tree
providerType: str = "gdal" # Provider key: "gdal", "wms", "wcs", "postgresraster"
)Returns a QgsRasterLayer instance. ALWAYS check isValid() after construction.
Note: When providerType is omitted, it defaults to "gdal". For WMS, WMTS, XYZ, or WCS layers, you MUST specify the provider explicitly.
---
QgsPointCloudLayer Constructor (QGIS 3.18+)
QgsPointCloudLayer(
uri: str, # Path to LAS/LAZ/COPC/EPT file
baseName: str = "", # Display name
providerLib: str = "pdal" # Provider key: "pdal", "copc", "ept"
)---
QgsMeshLayer Constructor
QgsMeshLayer(
path: str, # Path to mesh file (NetCDF, GRIB, etc.)
baseName: str = "", # Display name
providerLib: str = "mdal" # Provider key: "mdal"
)---
QgsVectorTileLayer Constructor
QgsVectorTileLayer(
uri: str, # URI string with type and url parameters
baseName: str = "" # Display name
)URI format: type=xyz&url=https://example.com/{z}/{x}/{y}.pbf&zmin=0&zmax=14
---
QgsDataSourceUri
Constructor
uri = QgsDataSourceUri()
# OR from existing URI string:
uri = QgsDataSourceUri(existing_uri_string)Connection Methods
uri.setConnection(
aHost: str, # Hostname or IP
aPort: str, # Port number as string
aDatabase: str, # Database name
aUsername: str, # Username
aPassword: str # Password
)
# With SSL mode
uri.setConnection(
aHost: str,
aPort: str,
aDatabase: str,
aUsername: str,
aPassword: str,
sslmode: QgsDataSourceUri.SslMode # SslDisable, SslAllow, SslPrefer, SslRequire, SslVerifyCa, SslVerifyFull
)Data Source Methods
uri.setDataSource(
aSchema: str, # Schema name (e.g., "public")
aTable: str, # Table or view name
aGeometryColumn: str, # Geometry column name
aSql: str = "", # Optional SQL WHERE filter
aKeyColumn: str = "" # Optional primary key column
)URI Generation
uri_string = uri.uri(expandAuthConfig: bool)
# expandAuthConfig=False → ALWAYS use this for logging/display (hides credentials)
# expandAuthConfig=True → NEVER use for logging (exposes credentials)Authentication Manager Integration
uri.setAuthConfigId(authcfg: str) # Use QGIS auth manager configuration IDGetter Methods
uri.host() # str
uri.port() # str
uri.database() # str
uri.username() # str
uri.password() # str
uri.schema() # str
uri.table() # str
uri.geometryColumn() # str
uri.keyColumn() # str
uri.sql() # str
uri.sslMode() # QgsDataSourceUri.SslModeSSL Mode Enum
QgsDataSourceUri.SslPrefer # Default
QgsDataSourceUri.SslDisable
QgsDataSourceUri.SslAllow
QgsDataSourceUri.SslRequire
QgsDataSourceUri.SslVerifyCa
QgsDataSourceUri.SslVerifyFull---
QgsProviderRegistry
Key Methods
registry = QgsProviderRegistry.instance()
registry.providerList() # list[str] — all registered provider keys
registry.providerMetadata(providerKey) # QgsProviderMetadata or None
registry.library(providerKey) # str — path to provider library
registry.pluginList() # str — formatted list of all providersQgsProviderMetadata
meta = registry.providerMetadata("ogr")
meta.key() # str — provider key
meta.description() # str — human-readable description
meta.supportedLayerTypes() # list — supported QgsMapLayerType values---
QgsDataProvider
Sublayer Discovery
provider = layer.dataProvider()
# Get sublayer list (for multi-layer sources like GeoPackage)
sublayers = provider.subLayers() # list[str]
# Sublayer string format: "{index}:{name}:{feature_count}:{geometry_type}:{srid}"
# Split with QgsDataProvider.SUBLAYER_SEPARATORConstants
QgsDataProvider.SUBLAYER_SEPARATOR # str — separator character for sublayer strings---
Layer Validity
isValid()
layer.isValid() # bool — True if layer loaded successfullyA layer is invalid when:
- File path does not exist or is inaccessible
- URI format is malformed for the provider
- Provider cannot parse the data format
- Authentication credentials are missing or incorrect
- CRS database is unavailable (standalone scripts without
setPrefixPath) - Required driver is not installed (e.g., ECW, MrSID)
Error Reporting
layer.error().summary() # str — human-readable error summary (QGIS 3.x)
layer.dataProvider() # None if provider failed to initialize