| name | arcgis-layers |
| description | Add and manage data layers in ArcGIS maps. Use for FeatureLayer, TileLayer, SceneLayer, GeoJSONLayer, and all other layer types. Covers layer configuration, queries, and management. |
ArcGIS Layers
Use this skill when adding, configuring, or querying data layers in ArcGIS maps.
Import Patterns
Direct ESM Imports
import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer.js";
import GeoJSONLayer from "@arcgis/core/layers/GeoJSONLayer.js";
Dynamic Imports (CDN)
const FeatureLayer = await $arcgis.import(
"@arcgis/core/layers/FeatureLayer.js",
);
const [GraphicsLayer, Graphic] = await $arcgis.import([
"@arcgis/core/layers/GraphicsLayer.js",
"@arcgis/core/Graphic.js",
]);
Layer Types Overview
| Layer Type | Use Case | Geometry |
|---|
| FeatureLayer | Most common - feature services, editable data | Points, lines, polygons |
| GraphicsLayer | Client-side temporary graphics | Any |
| GeoJSONLayer | GeoJSON files/URLs | Points, lines, polygons |
| CSVLayer | CSV files with coordinates | Points |
| TileLayer | Cached map tiles | Raster |
| VectorTileLayer | Vector tiles (Mapbox style) | Vector |
| ImageryTileLayer | Raster imagery | Raster |
| SceneLayer | 3D buildings, meshes | 3D objects |
| IntegratedMeshLayer | Photogrammetry meshes | 3D mesh |
| PointCloudLayer | LiDAR point clouds | Points |
| ParquetLayer | Apache Parquet files | Points, lines, polygons |
| StreamLayer | Real-time WebSocket data | Points, lines, polygons |
FeatureLayer
From URL
import FeatureLayer from "@arcgis/core/layers/FeatureLayer.js";
const featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0",
outFields: ["*"],
popupTemplate: {
title: "{Tree_ID}",
content: "Height: {Crown_Height} ft",
},
});
map.add(featureLayer);
From Portal Item
const featureLayer = new FeatureLayer({
portalItem: {
id: "51c851fef66143959986b473b345b7ca",
},
outFields: ["*"],
});
Client-Side (In-Memory)
const featureLayer = new FeatureLayer({
source: graphics,
fields: [
{ name: "ObjectID", type: "oid" },
{ name: "name", type: "string" },
{ name: "value", type: "double" },
],
objectIdField: "ObjectID",
geometryType: "point",
spatialReference: { wkid: 4326 },
renderer: {
type: "simple",
symbol: { type: "simple-marker", color: "blue" },
},
});
Configuration Options
const featureLayer = new FeatureLayer({
url: "...",
outFields: ["*"],
definitionExpression: "population > 10000",
minScale: 500000,
maxScale: 0,
visible: true,
opacity: 0.8,
title: "Cities",
blendMode: "normal",
orderBy: [{ field: "population" }],
featureReduction: null,
labelingInfo: [...],
renderer: {...},
popupTemplate: {...},
elevationInfo: {
mode: "relative-to-ground"
}
});
GraphicsLayer
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer.js";
import Graphic from "@arcgis/core/Graphic.js";
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
const pointGraphic = new Graphic({
geometry: {
type: "point",
longitude: -118.24,
latitude: 34.05,
},
symbol: {
type: "simple-marker",
color: "red",
size: 12,
},
attributes: { name: "Los Angeles" },
popupTemplate: { title: "{name}" },
});
graphicsLayer.add(pointGraphic);
graphicsLayer.addMany([graphic1, graphic2, graphic3]);
graphicsLayer.remove(pointGraphic);
graphicsLayer.removeAll();
GeoJSONLayer
import GeoJSONLayer from "@arcgis/core/layers/GeoJSONLayer.js";
const geojsonLayer = new GeoJSONLayer({
url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson",
copyright: "USGS Earthquakes",
popupTemplate: {
title: "Earthquake Info",
content: "Magnitude {mag} hit {place} on {time}",
fieldInfos: [
{
fieldName: "time",
format: { dateFormat: "short-date-short-time" },
},
],
},
renderer: {
type: "simple",
symbol: { type: "simple-marker", color: "orange" },
visualVariables: [
{
type: "size",
field: "mag",
stops: [
{ value: 2.5, size: "4px" },
{ value: 8, size: "40px" },
],
},
],
},
orderBy: [{ field: "mag" }],
});
map.add(geojsonLayer);
CSVLayer
import CSVLayer from "@arcgis/core/layers/CSVLayer.js";
const csvLayer = new CSVLayer({
url: "https://example.com/data.csv",
latitudeField: "latitude",
longitudeField: "longitude",
delimiter: ",",
popupTemplate: {
title: "{name}",
content: "{description}",
},
});
TileLayer (Cached Tiles)
import TileLayer from "@arcgis/core/layers/TileLayer.js";
const tileLayer = new TileLayer({
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer",
});
map.add(tileLayer);
VectorTileLayer
import VectorTileLayer from "@arcgis/core/layers/VectorTileLayer.js";
const vtl = new VectorTileLayer({
portalItem: { id: "VECTOR_TILE_ITEM_ID" },
});
const vtl2 = new VectorTileLayer({
url: "https://basemaps.arcgis.com/v1/arcgis/rest/services/World_Basemap/VectorTileServer",
});
ImageryTileLayer
import ImageryTileLayer from "@arcgis/core/layers/ImageryTileLayer.js";
const imageryLayer = new ImageryTileLayer({
url: "https://tiledimageservices.arcgis.com/...",
});
const cogLayer = new ImageryTileLayer({
url: "https://example.com/image.tif",
});
3D Layers
SceneLayer (3D Buildings)
import SceneLayer from "@arcgis/core/layers/SceneLayer.js";
const sceneLayer = new SceneLayer({
portalItem: { id: "2e0761b9a4274b8db52c4bf34356911e" },
popupEnabled: false,
});
map.add(sceneLayer);
sceneLayer.renderer = {
type: "simple",
symbol: {
type: "mesh-3d",
symbolLayers: [
{
type: "fill",
material: { color: [244, 247, 134] },
},
],
},
};
IntegratedMeshLayer
import IntegratedMeshLayer from "@arcgis/core/layers/IntegratedMeshLayer.js";
const meshLayer = new IntegratedMeshLayer({
url: "https://tiles.arcgis.com/tiles/.../IntegratedMeshServer",
});
PointCloudLayer
import PointCloudLayer from "@arcgis/core/layers/PointCloudLayer.js";
const pcLayer = new PointCloudLayer({
url: "https://tiles.arcgis.com/tiles/.../SceneServer",
});
Specialized Layers
For WMS, WFS, KML, MapImageLayer, and CatalogLayer, see arcgis-advanced-layers.
StreamLayer (Real-time)
import StreamLayer from "@arcgis/core/layers/StreamLayer.js";
const streamLayer = new StreamLayer({
url: "wss://example.com/stream/service",
purgeOptions: {
displayCount: 10000,
},
});
ParquetLayer (File-based)
import ParquetLayer from "@arcgis/core/layers/ParquetLayer.js";
const parquetLayer = new ParquetLayer({
urls: ["https://example.com/data.parquet"],
title: "Parquet Data",
renderer: {
type: "simple",
symbol: { type: "simple-marker", color: "blue" },
},
popupTemplate: {
title: "{name}",
content: [
{
type: "fields",
fieldInfos: [{ fieldName: "field1", label: "Field 1" }],
},
],
},
});
const count = await parquetLayer.queryFeatureCount();
GeoRSSLayer
import GeoRSSLayer from "@arcgis/core/layers/GeoRSSLayer.js";
const georssLayer = new GeoRSSLayer({
url: "https://example.com/feed.xml",
});
map.add(georssLayer);
await view.whenLayerView(georssLayer);
view.goTo(georssLayer.fullExtent);
WebTileLayer
import WebTileLayer from "@arcgis/core/layers/WebTileLayer.js";
const osmLayer = new WebTileLayer({
urlTemplate: "https://{subDomain}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subDomains: ["a", "b", "c"],
copyright: "OpenStreetMap contributors",
});
const customTileLayer = new WebTileLayer({
urlTemplate: "https://tiles.example.com/{level}/{col}/{row}.png",
});
map.add(osmLayer);
MapNotesLayer
import MapNotesLayer from "@arcgis/core/layers/MapNotesLayer.js";
const notesLayer = new MapNotesLayer();
map.add(notesLayer);
const pointLayer = notesLayer.pointLayer;
const polylineLayer = notesLayer.polylineLayer;
const polygonLayer = notesLayer.polygonLayer;
const textLayer = notesLayer.textLayer;
const textGraphic = new Graphic({
geometry: point,
symbol: {
type: "text",
text: "Note here",
color: [255, 255, 255],
haloColor: [0, 0, 0],
haloSize: 2,
font: { family: "Arial", size: 14 },
},
});
textLayer.add(textGraphic);
Layer Management
Adding Layers
map.add(layer);
map.add(layer, 0);
map.addMany([layer1, layer2, layer3]);
const viewElement = document.querySelector("arcgis-map");
viewElement.map.add(layer);
Removing Layers
map.remove(layer);
map.removeMany([layer1, layer2]);
map.removeAll();
Layer Ordering
map.reorder(layer, newIndex);
const index = map.layers.indexOf(layer);
const layer = map.findLayerById("myLayerId");
const layer = map.layers.find((l) => l.title === "Cities");
Visibility and Opacity
layer.visible = false;
layer.opacity = 0.5;
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";
reactiveUtils.watch(
() => layer.visible,
(newValue) => console.log("Visibility changed:", newValue),
);
Querying Features
Basic Query
const query = featureLayer.createQuery();
query.where = "population > 100000";
query.outFields = ["name", "population"];
query.returnGeometry = true;
const result = await featureLayer.queryFeatures(query);
console.log(result.features);
Query with Pagination
const query = featureLayer.createQuery();
query.start = 0;
query.num = 20;
query.orderByFields = ["population DESC"];
const result = await featureLayer.queryFeatures(query);
Spatial Query
const query = featureLayer.createQuery();
query.geometry = view.extent;
query.spatialRelationship = "intersects";
query.returnGeometry = true;
const result = await featureLayer.queryFeatures(query);
Count Query
const count = await featureLayer.queryFeatureCount();
console.log("Total features:", count);
Extent Query
const result = await featureLayer.queryExtent();
console.log("Feature count:", result.count);
await view.goTo(result.extent);
Statistics Query
const query = featureLayer.createQuery();
query.outStatistics = [
{
statisticType: "sum",
onStatisticField: "population",
outStatisticFieldName: "totalPop",
},
{
statisticType: "avg",
onStatisticField: "population",
outStatisticFieldName: "avgPop",
},
];
const result = await featureLayer.queryFeatures(query);
console.log(result.features[0].attributes.totalPop);
Query from LayerView (Client-side)
const layerView = await view.whenLayerView(featureLayer);
const query = layerView.createQuery();
query.geometry = view.extent;
const result = await layerView.queryFeatures(query);
Query Methods Reference
| Method | Returns | Use When |
|---|
queryFeatures(query) | FeatureSet (graphics) | You need the actual feature data |
queryObjectIds(query) | number[] (OIDs) | You only need IDs for highlighting |
queryFeatureCount(query) | number | You need a count without fetching data |
queryExtent(query) | { count, extent } | You want to zoom to matching features |
queryRelatedFeatures(params) | Related feature sets | You need related table records |
queryAttachments(params) | AttachmentInfo[] | You need file attachments |
Server vs Client-side Queries
| Aspect | featureLayer.queryFeatures() | layerView.queryFeatures() |
|---|
| Runs on | Server | Client (browser) |
| Data scope | All features in service | Only features in view/cache |
| Network cost | HTTP request per call | No network (already loaded) |
| Use when | Need full dataset, pagination, stats | Need fast filtering of visible features |
Layer Loading
await featureLayer.load();
console.log("Fields:", featureLayer.fields);
console.log("Extent:", featureLayer.fullExtent);
const layerView = await view.whenLayerView(featureLayer);
reactiveUtils.watch(
() => layerView.updating,
(updating) => {
if (!updating) {
console.log("Layer view finished updating");
}
},
);
Definition Expressions (Filters)
featureLayer.definitionExpression = "state = 'California'";
featureLayer.definitionExpression = null;
function filterByYear(year) {
featureLayer.definitionExpression = `year = ${year}`;
}
TypeScript Usage
Layer configurations with type properties support autocasting. For TypeScript safety, use as const:
const featureLayer = new FeatureLayer({
source: graphics,
fields: [
{ name: "ObjectID", type: "oid" },
{ name: "name", type: "string" },
],
geometryType: "point",
renderer: {
type: "simple",
symbol: { type: "simple-marker", color: "blue" },
} as const,
});
For complex layer configurations, use type annotations:
const renderer: __esri.SimpleRendererProperties = {
type: "simple",
symbol: { type: "simple-marker", color: "blue" },
};
layer.renderer = renderer;
Tip: See arcgis-core-maps for detailed guidance on autocasting vs explicit classes.
Reference Samples
intro-layers - Introduction to working with layers
layers-featurelayer - FeatureLayer configuration and usage
layers-geojson - Loading GeoJSON data as a layer
featurelayer-query - Querying features from a FeatureLayer
get-started-graphics - Working with Graphics and GraphicsLayer
Related Skills
- See
arcgis-core-maps for map and view setup.
- See
arcgis-visualization for renderers, symbols, and visual variables.
- See
arcgis-popup-templates for popup configuration.
- See
arcgis-editing for feature editing with applyEdits.
- See
arcgis-advanced-layers for WMS, WFS, KML, MapImageLayer, CatalogLayer.
- See
arcgis-3d-layers for 3D-specific layer configuration.
Common Pitfalls
-
CORS errors with GeoJSON: GeoJSON URLs must be CORS-enabled or use a proxy.
-
Missing outFields: Queries return no attribute values unless outFields is specified.
const results = await featureLayer.queryFeatures({
where: "population > 100000",
returnGeometry: true,
});
console.log(results.features[0].attributes.name);
const results = await featureLayer.queryFeatures({
where: "population > 100000",
returnGeometry: true,
outFields: ["name", "population", "state"],
});
console.log(results.features[0].attributes.name);
Impact: Feature attributes come back as undefined or null. The query succeeds but the response contains no usable attribute data, leading to silent data bugs.
-
Not waiting for layer load: Layer metadata (fields, extent, renderer) is unavailable until the layer finishes loading.
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
console.log(layer.fields);
console.log(layer.fullExtent);
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
await layer.load();
console.log(layer.fields);
console.log(layer.fullExtent);
Impact: fields is null or an empty array, fullExtent is null, and any code that depends on layer metadata throws errors or silently fails.
-
Wrong layer for MapView vs SceneView: Some layers only work in 3D (SceneLayer, IntegratedMeshLayer, PointCloudLayer).
-
Spatial reference mismatch: Adding layers with a different spatial reference than the view without projection support.
const view = new MapView({
spatialReference: { wkid: 4326 },
});
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
view.map.add(layer);
import * as projection from "@arcgis/core/geometry/projection.js";
await projection.load();
const view = new MapView({
spatialReference: { wkid: 4326 },
});
const layer = new FeatureLayer({
url: "https://services.arcgis.com/.../FeatureServer/0",
});
view.map.add(layer);
Impact: Features appear in the wrong location, are offset by thousands of kilometers, or do not display at all when spatial references are incompatible.