Short answer
These three OGC standards answer different questions. WMS (Web Map Service) hands you a rendered image — pixels, already styled, for display. WFS (Web Feature Service) hands you the raw vector features — geometry plus attributes — so you can query, measure, edit, and analyze. OGC API Features is the modern successor to WFS: the same goal of serving feature data, but over a clean REST/JSON/OpenAPI design instead of WFS's XML machinery. Choose by what you need to do with the data, not by which is newest.
WMS — server renders, you display
A WMS draws the data on the server and returns a picture (PNG, JPEG, WebP). The client never sees the geometry; it sees the cartography the server chose. The core operations are:
GetCapabilities— the service describes its layers, supported CRSs, formats, and styles.GetMap— request an image for a bounding box, size, CRS, and layers.GetFeatureInfo— ask "what is at this pixel?" and get back attributes for the feature under a point.
A typical GetMap request:
https://example.org/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap
&LAYERS=geology&CRS=EPSG:3857&BBOX=...&WIDTH=1024&HEIGHT=768&FORMAT=image/png
WMS is ideal when you want a polished overlay or basemap without shipping (or exposing) the underlying data, when the dataset is huge and you only need a view, or when consistent server-side styling matters. Its limits: you cannot select, measure, re-style, or analyze the features, because you only have pixels. Note the axis-order trap — WMS 1.3.0 uses the authority-defined axis order for geographic CRSs (latitude first for EPSG:4326), whereas WMS 1.1.1 used longitude first. A version mismatch shifts the whole map.
For pre-tiled images there is also WMTS (Web Map Tile Service), a cache-friendly cousin of WMS that serves fixed tile pyramids for fast, scalable basemaps.
WFS — server sends features, you do the work
A WFS returns the actual vector data, historically as GML (an XML geography format), and often also GeoJSON. Core operations:
GetCapabilities— describe feature types.DescribeFeatureType— return the attribute schema (field names and types).GetFeature— return features, optionally filtered, sorted, and limited.
A GetFeature request with a filter:
https://example.org/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature
&TYPENAMES=faults&COUNT=500&SRSNAME=EPSG:25831
&CQL_FILTER=type='thrust'&OUTPUTFORMAT=application/json
Because you receive real geometry, you can run client-side selection, spatial analysis, snapping, and measurement. WFS-T (Transactional WFS) adds Insert, Update, and Delete, turning the service into an editing endpoint. WFS is the right tool when the client genuinely needs the data: digitizing against a reference layer, computing intersections, extracting a subset for offline use, or feeding an analysis pipeline. Its cost is payload size and complexity — GML is verbose, and large requests are heavy. Like WMS, WFS has version-dependent axis-order behavior: WFS 1.0.0 returned longitude/latitude, while 1.1.0 and 2.0.0 follow the authority order.
OGC API Features — the modern REST replacement
OGC API Features (its first part is also an ISO standard) keeps WFS's purpose but rebuilds the interface around current web practice: REST resources, JSON/GeoJSON by default, OpenAPI for self-description, and ordinary HTTP query parameters instead of long key-value or XML-POST requests. The resource model is intuitive:
GET /collections -> list of available datasets
GET /collections/faults -> metadata for one collection
GET /collections/faults/items?bbox=...&limit=500 -> features as GeoJSON
GET /collections/faults/items/{id} -> a single feature
Filtering by bounding box, datetime, and attribute is built in; richer querying comes via the Filter extension (CQL2), and create/update/delete via the Transactions extension. Coordinates default to WGS84 longitude/latitude following the GeoJSON convention, sidestepping much of the axis-order pain. It is far easier for a JavaScript or Python developer to consume — fetch() a URL, get GeoJSON, render it — which is why OGC is steering new feature services toward it. For raster and coverage data the family extends to OGC API Tiles, Maps, and Coverages, the modern analogues of WMTS/WMS.
Worked example — choosing for a real task
Suppose you publish a regional fault dataset and three consumers need it:
- A public web viewer that just shows faults over a topographic basemap, styled consistently → WMS (or WMTS tiles for speed). They never need the geometry.
- A consultant's QGIS project where the analyst snaps new boreholes to faults and computes distances → WFS or OGC API Features, because they need real geometry and the schema.
- A new web app built by frontend developers who want GeoJSON straight into MapLibre and a clean filter API → OGC API Features, for the REST/JSON ergonomics.
One dataset, three correct answers, driven entirely by what each client does with it.
Performance and practical considerations
- Payload: WMS sends a fixed-size image regardless of feature count; WFS/OGC API Features payload grows with the number and complexity of features. Always paginate (
COUNT/limit) and filter (bbox, attribute filters) on feature services. - Caching: rendered tiles (WMTS, OGC API Tiles) cache beautifully; feature responses cache less well but support conditional requests.
- Styling: WMS styling lives on the server (SLD); feature services leave styling to the client.
- CRS: request an explicit CRS and confirm axis order, especially when mixing service versions in one map.
Validation
- Call
GetCapabilities(WMS/WFS) orGET /and/conformance(OGC API Features) first and confirm the layer name, available CRSs, and output formats before wiring up requests. - For feature services, fetch a small
limit/COUNTand verify the geometry lands in the right place — a swap means an axis-order or CRS mismatch. - Confirm the output format your client expects is actually advertised (GeoJSON is not guaranteed on every WFS).
Common pitfalls and why they happen
- Using WMS when you needed the data. The map looks right but you cannot query or edit it, because you only have pixels.
- Pulling an unfiltered WFS layer and timing out. Without
bbox/COUNTthe server tries to serialize everything. Always constrain the request. - Axis-order shifts across versions. WMS 1.1.1 vs 1.3.0 and WFS 1.0.0 vs 2.0.0 differ on lat/lon order for geographic CRSs; pin the version and verify placement.
- Assuming OGC API Features and WFS are interchangeable on the wire. They share intent, not syntax — a WFS client cannot talk to an OGC API Features endpoint without an adapter.
Bathyl perspective
We pick the service by the consumer's job: pixels for viewers, features for analysts and editors, and OGC API Features when the client is a modern web app. Each published endpoint carries its CRS, axis convention, and recommended filters in its metadata, so a consumer can integrate it without trial and error. Serving the wrong abstraction — a heavy feature service to a viewer, or a flat image to an analyst — is the most common and most avoidable integration failure.
Related reading
- GeoJSON Coordinate Order Explained
- Why Coordinates Look Reversed in GIS Data
- When to Use PostGIS Instead of Files
- Spatial data products