esri-gl

June 8, 2026 · View on GitHub

A TypeScript library that bridges Esri ArcGIS REST services with MapLibre GL JS and Mapbox GL JS.

npm version CI TypeScript License: MIT

Documentation · Live Demos · npm

Features

Services

  • DynamicMapService — Server-rendered raster tiles with dynamic styling, filtering, labeling, and identify
  • TiledMapService — Pre-cached tiles for fast basemaps
  • ImageService — Analytical raster data with rendering rules and temporal support
  • FeatureService — Vector data with smart vector tile detection, GeoJSON fallback, editing, and attachments
  • VectorTileService — Client-rendered vector tiles
  • VectorBasemapStyle — Esri's professional basemap styles

Tasks

  • IdentifyFeatures / IdentifyImage — Query features and pixel values at map locations
  • Query — Spatial and attribute queries with automatic pagination
  • Find — Text-based feature search across layers

Integrations

  • React HooksuseDynamicMapService, useFeatureService, useQuery, etc.
  • react-map-gl — Declarative <EsriDynamicLayer>, <EsriFeatureLayer>, etc.
  • TypeScript — Full type safety with comprehensive interfaces

Built on ArcGIS REST JS

  • Official client — requests, authentication, and feature editing run on @esri/arcgis-rest-js (-request, -feature-service, -portal, -basemap-sessions)
  • Flexible authtoken, apiKey, or any IAuthenticationManager (ApiKeyManager, ArcGISIdentityManager, …) on every service and task
  • Portal item resolution — turn a portal item id or Web Map into ready-to-render services

Installation

npm install esri-gl

Entry Points

ImportUse Case
esri-glCore services and tasks
esri-gl/reactReact hooks
esri-gl/react-map-glreact-map-gl components

CDN (UMD)

<script src="https://unpkg.com/esri-gl@latest/dist/index.umd.js"></script>
<script>
  const service = new esrigl.DynamicMapService('source', map, { url: '...' });
</script>

Quick Start

import { DynamicMapService } from 'esri-gl';

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json',
  center: [-95, 37],
  zoom: 4
});

map.on('load', () => {
  const service = new DynamicMapService('usa-source', map, {
    url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer',
    layers: [0, 1, 2],
    transparent: true
  });

  map.addLayer({ id: 'usa-layer', type: 'raster', source: 'usa-source' });
});

Service Examples

FeatureService

const service = new FeatureService('features-source', map, {
  url: 'https://services.arcgis.com/.../FeatureServer/0',
  where: "STATUS = 'Active'",
  outFields: 'NAME,STATUS',
  token: 'your-token' // optional
});

map.addLayer({
  id: 'features-layer',
  type: 'circle',
  source: 'features-source',
  paint: { 'circle-radius': 5, 'circle-color': '#007cbf' }
});

// Edit features
await service.addFeatures([feature]);
await service.applyEdits({ adds: [], updates: [], deletes: [1, 2] });

ImageService

const service = new ImageService('landsat-source', map, {
  url: 'https://landsat2.arcgis.com/arcgis/rest/services/Landsat/MS/ImageServer',
  renderingRule: { rasterFunction: 'Natural Color' }
});

VectorBasemapStyle

VectorBasemapStyle.applyStyle(map, 'arcgis/streets', { apiKey: 'YOUR_KEY' });

Tasks

import { IdentifyFeatures, query } from 'esri-gl';

// Identify features at a point
const results = await new IdentifyFeatures('https://.../MapServer')
  .at({ lng: -95, lat: 37 })
  .on(map)
  .layers('all')
  .tolerance(5)
  .run();

// Query with pagination
const all = await query({ url: 'https://.../FeatureServer/0' })
  .where("STATE_NAME = 'California'")
  .runAll();

Authentication

Every service and task accepts token, apiKey, or an authentication manager (precedence: authenticationapiKeytoken). esri-gl uses ArcGIS REST JS's authentication managers under the hood.

import { DynamicMapService, ArcGISIdentityManager, ApiKeyManager } from 'esri-gl';

// API key or static token
new DynamicMapService('source', map, { url, apiKey: 'AAPK…' });
new DynamicMapService('source', map, { url, token: 'eyJ…' });

// Named-user session with auto-refreshing token
const session = await ArcGISIdentityManager.signIn({ username, password });
new FeatureService('source', map, { url, authentication: session });

See the Authentication guide for the authenticationrequired event, the esriRequest/resolveAuthentication helpers, and migration notes.

Portal Items & Web Maps

Resolve an ArcGIS portal item id — or a whole Web Map — straight to esri-gl services (powered by @esri/arcgis-rest-portal):

import { serviceFromPortalItem, servicesFromWebMap } from 'esri-gl';

// Single item → the matching service (Feature/Map/Image/Vector Tile)
const { service, kind } = await serviceFromPortalItem('my-source', map, itemId, { apiKey });
map.addLayer({ id: 'my-layer', type: 'raster', source: 'my-source' });

// Web Map → a service per operational layer
const layers = await servicesFromWebMap(map, webMapItemId, { token });

See the Portal Items guide for the item-type/layer-type mappings and options.

React Integration

Hooks

import { useDynamicMapService, useIdentifyFeatures } from 'esri-gl/react';

const { service, loading, error } = useDynamicMapService({
  sourceId: 'usa-service',
  map,
  options: {
    url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer',
    layers: [0, 1, 2]
  }
});

react-map-gl Components

import { EsriDynamicLayer, EsriFeatureLayer } from 'esri-gl/react-map-gl';

<Map mapStyle="mapbox://styles/mapbox/streets-v11">
  <EsriDynamicLayer
    id="census"
    url="https://.../Census/MapServer"
    layers={[0, 1]}
    opacity={0.8}
    token="YOUR_TOKEN"
  />
  <EsriFeatureLayer
    id="states"
    url="https://.../FeatureServer/0"
    paint={{ 'fill-color': '#627BC1', 'fill-opacity': 0.6 }}
  />
</Map>

All layer components accept token, apiKey, authentication, getAttributionFromService, and requestParams for authenticated services and custom request behavior.

Examples

Working examples in examples/:

ExampleDescription
maplibre-esmAll services and tasks with vanilla MapLibre
maplibre-react-hooksReact hooks with MapLibre
maplibre-react-map-glreact-map-gl components
cd examples/maplibre-esm && npm install && npm run dev

Development

npm run dev          # Start demo dev server
npm run build        # Build library (ESM + UMD)
npm run test         # Run tests (733 tests, 31 suites)
npm run type-check   # TypeScript check
npm run lint         # ESLint
npm run build:docs   # Build documentation site
npm run build:demo   # Build demo site

Contributing

  1. Fork and create a feature branch
  2. Make changes and add tests
  3. Run npm run test && npm run type-check && npm run lint
  4. Submit a pull request

Pre-commit hooks automatically run formatting, linting, and tests via Husky.

Support

Buy Me A Coffee

License

MIT — see LICENSE

Acknowledgements