diff --git a/workshop/content/docs/advanced/arcgis.md b/workshop/content/docs/advanced/arcgis.md
index 1486565..ebeae88 100644
--- a/workshop/content/docs/advanced/arcgis.md
+++ b/workshop/content/docs/advanced/arcgis.md
@@ -183,7 +183,7 @@ labelsCheckbox.addEventListener('change', (event) => {
--8<-- "arcgis.js"
```
-??? Mapfile "stac.map"
+??? Mapfile "arcgis.map"
``` scala
--8<-- "arcgis.map"
diff --git a/workshop/content/docs/advanced/gdalg.md b/workshop/content/docs/advanced/gdalg.md
new file mode 100644
index 0000000..78b1dca
--- /dev/null
+++ b/workshop/content/docs/advanced/gdalg.md
@@ -0,0 +1,138 @@
+# Working with GDAL Vector Pipelines
+
+## Overview
+
+MapServer can dynamically run a [GDAL Vector Pipeline](https://gdal.org/en/latest/programs/gdal_vector_pipeline.html), and render its output -
+all through a simple Mapfile.
+
+In this workshop we'll use the Tartu roads dataset used in the [Line Styling](../mapfile/lines.md) exercise, dynamically
+buffer it using GDAL, and display the result in OpenLayers using a MapServer WMS.
+
+This is a simple example of a pipeline, but additional steps can be chained together to create more complex workflows.
+MapServer reads a vector pipeline using the [GDALG: GDAL Streamed Algorithm](https://gdal.org/en/latest/drivers/vector/gdalg.html) driver.
+
+
+
+
+
+## Checking the Pipelines with GDAL
+
+Before configuring MapServer, it is often easier to test your pipelines directly with GDAL, to ensure they run correctly.
+Run the commands below to connect to the MapServer Docker container and use GDAL to get information about the pipelines.
+
+```bash
+# open a shell inside the MapServer container
+docker exec -it mapserver /bin/bash
+
+# check the dataset used in the pipeline
+gdal vector info data/osm/roads.fgb
+
+# inspect the a pipeline JSON file included in the container
+gdal vector info roads.gdalg.json
+
+# test an inline pipeline using a single-quoted string (recommended)
+gdal vector info '{"type": "gdal_streamed_alg","command_line": "gdal vector pipeline ! read /etc/mapserver/data/osm/roads.fgb ! geom buffer --distance=0.0001"}'
+
+# alternatively escape the double quotes
+gdal vector info "{\"type\": \"gdal_streamed_alg\",\"command_line\": \"gdal vector pipeline ! read data/osm/roads.fgb ! geom buffer --distance=0.0001\"}"
+```
+
+## The Mapfile
+
+### Embedding Pipelines in a Mapfile
+
+The pipeline `LAYER` in this example uses `CONNECTIONTYPE OGR` and includes the GDAL pipeline "inline" - meaning the pipeline is defined
+directly in the Mapfile. Our example pipeline looks like this:
+
+```scala
+CONNECTION '{"type": "gdal_streamed_alg","command_line": "gdal vector pipeline ! read /etc/mapserver/data/osm/roads.fgb ! geom buffer --distance=0.0001"}'
+DATA "0"
+```
+
+Key points to note:
+
+- `DATA "0"` tells MapServer to use the first (index 0) layer in the connection. Since the pipeline returns a single dataset, this will correspond
+ to the buffered roads.
+- When using an inline GDAL pipeline, you must provide the absolute path to any datasets used by the pipeline.
+- GDAL requires a valid JSON string for the pipeline. All property names and string values must use double quotes.
+
+In a Mapfile, you have two options for embedding JSON:
+
+1. Wrap the JSON string in single quotes (as in the example above) - this is simpler and easier to read or copy/paste.
+2. Escape the double quotes using `\"` as in the example below:
+
+ ```scala
+ CONNECTION "{\"type\": \"gdal_streamed_alg\",\"command_line\": \"gdal vector pipeline ! read /etc/mapserver/data/osm/roads.fgb ! geom buffer --distance=0.0001\"}"
+ ```
+
+### Referencing Pipelines in a JSON File
+
+MapServer can also reference a JSON file containing a pipeline, which makes it easy to test and reuse the pipeline with GDAL.
+By convention GDALG files should use the `.gdalg.json` extension.
+
+```scala
+CONNECTION "roads.gdalg.json"
+DATA "0"
+```
+
+The contents of pipeline JSON file `roads.gdalg.json` are shown below. Notice that the dataset path `data/osm/roads.fgb` is relative to the JSON file.
+
+Using relative paths in a JSON file makes the pipeline more portable, because it can be moved to a different folder or system without changing the dataset paths.
+
+```json
+{
+ "type": "gdal_streamed_alg",
+ "command_line": "gdal vector pipeline ! read data/osm/roads.fgb ! geom buffer --distance=0.0001"
+}
+```
+
+### Hatch Styling
+
+Finally, we use a [hatch symbol](https://mapserver.org/mapfile/symbol.html#mapfile-symbol-type) to style the buffered roads.
+Hatch symbols allow you to add patterned fills, and you can adjust their angle, width, and size in the [STYLE](https://mapserver.org/mapfile/style.html) block.
+
+```scala
+SYMBOL
+ NAME "hatchsymbol"
+ TYPE hatch
+END
+...
+LAYER
+ CLASS
+ STYLE
+ SYMBOL "hatchsymbol"
+ COLOR "#78C8FF"
+ WIDTH 0.1
+ ANGLE 45
+ SIZE 8
+ END
+```
+
+## Code
+
+!!! example
+
+ - Direct MapServer request:
+ - Local OpenLayers example:
+
+??? JavaScript "gdalg.js"
+
+ ``` js
+ --8<-- "gdalg.js"
+ ```
+
+??? Mapfile "gdalg.map"
+
+ ``` scala
+ --8<-- "gdalg.map"
+ ```
+
+## Exercises
+
+1. Switch to using the JSON file - replace the inline GDAL pipeline with `roads.gdalg.json` in your Mapfile.
+
+2. Extend the GDAL pipeline - add another processing step to the pipeline.
+ Refer to the [GDAL Vector Pipeline documentation](https://gdal.org/en/latest/programs/gdal_vector_pipeline.html) for examples of available operations.
+
+3. Experiment with hatch styling - adjust properties such as `ANGLE` and `SIZE` in your `STYLE` block
+ to see how the hatch pattern changes.
diff --git a/workshop/content/mkdocs.yml b/workshop/content/mkdocs.yml
index 6a4738f..481a599 100644
--- a/workshop/content/mkdocs.yml
+++ b/workshop/content/mkdocs.yml
@@ -30,6 +30,7 @@ nav:
- OGC API - Features: outputs/ogcapi-features.md
- Advanced:
- ArcGIS Feature Server: advanced/arcgis.md
+ - GDAL Pipeline: advanced/gdalg.md
- Vector Symbols: advanced/symbols.md
- Clusters: advanced/clusters.md
- SLD: advanced/sld.md
diff --git a/workshop/exercises/app/gdalg.html b/workshop/exercises/app/gdalg.html
new file mode 100644
index 0000000..b3e18e1
--- /dev/null
+++ b/workshop/exercises/app/gdalg.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ GDAL Vector Pipeline
+
+
+
+
+
+
diff --git a/workshop/exercises/app/index.html b/workshop/exercises/app/index.html
index e4e0c5f..ac0d767 100644
--- a/workshop/exercises/app/index.html
+++ b/workshop/exercises/app/index.html
@@ -30,9 +30,10 @@