Skip to content
GEOSAT
Back to blog
Open GIS
Open GIS2026-09-23GEOSAT4 min read

GeoServer SLD styles and labels: from a rule to a verifiable map

Define server-side symbols and labels and test their behavior by scale and density.

Editorial review: 2026-09-23

GeoServerSLDOpen GIS

A successful style migration preserves a map's meaning at its intended scales. Copying a fill color is not enough when categories, missing values, label priority or printed output influence decisions. GeoServer styles should be reviewed against a small cartographic specification, not a single favorable screenshot.

Separate data problems from styling problems

First publish the synthetic layer from the PostGIS/GeoServer tutorial and confirm its WFS attributes. This exercise uses publish:parcels, geometry geom, identifier parcel_id, and status values review and approved. If a source uses numeric domain codes, decide whether the published view exposes codes, labels or both. An SLD filter on a translated label will not match a stored integer.

Document the map purpose, supported scales, category labels and exceptions. For a cadastral review map, orange might mean “requires review” and green “approved”; those are fictional exercise meanings, not official regulatory colors. Include an outline and a text label so color is not the only way to distinguish important records.

Begin with one complete style

Save this as parcels.sld, add an SLD style in GeoServer and validate it before assigning it to the layer. It draws an orange polygon with a dark boundary and an identifier label. It deliberately avoids category rules until the basic rendering works.

Code example
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
 xmlns="http://www.opengis.net/sld"
 xmlns:ogc="http://www.opengis.net/ogc">
 <NamedLayer>
  <Name>parcels</Name>
  <UserStyle>
   <Title>Synthetic parcel review</Title>
   <FeatureTypeStyle>
    <Rule>
     <PolygonSymbolizer>
      <Fill><CssParameter name="fill">#F1A340</CssParameter></Fill>
      <Stroke>
       <CssParameter name="stroke">#25322D</CssParameter>
       <CssParameter name="stroke-width">1</CssParameter>
      </Stroke>
     </PolygonSymbolizer>
     <TextSymbolizer>
      <Label><ogc:PropertyName>parcel_id</ogc:PropertyName></Label>
      <Font>
       <CssParameter name="font-family">SansSerif</CssParameter>
       <CssParameter name="font-size">12</CssParameter>
      </Font>
      <Halo><Radius>1</Radius><Fill>
       <CssParameter name="fill">#FFFFFF</CssParameter>
      </Fill></Halo>
      <Fill><CssParameter name="fill">#25322D</CssParameter></Fill>
     </TextSymbolizer>
    </Rule>
   </FeatureTypeStyle>
  </UserStyle>
 </NamedLayer>
</StyledLayerDescriptor>

The SLD polygon cookbook and labeling reference document the building blocks. This example is an original minimal style; your fonts and GeoServer version still need local verification.

Add categories and scale rules one change at a time

Create a separate rule for each status using an OGC property-equality filter. Give rules human-readable titles so the legend has meaning. Add an explicit fallback for unexpected or null values; otherwise a data-quality problem can become an invisible polygon. Test all categories with a fixture containing every value before using a production dataset.

Decide at what scale identifiers remain readable. Add minimum/maximum scale denominators only after testing three deliberate views: regional overview, neighborhood and parcel detail. A symbol defined in pixels behaves differently from a ground-distance representation; choose according to the task. Avoid interpreting a change in line appearance as a geometry error until scale and output dimensions are fixed.

Compare server output and the consuming application

Use one WMS GetMap request with fixed bbox, CRS, width and height for repeatable review. Save a baseline image and change one style property at a time. Request the legend separately and compare category order, text and swatches. Then inspect the map in QGIS or the web viewer at matching extents.

CheckPassing behaviorCommon failure
Category coverageEvery expected value drawsStored code differs from label filter
Missing valueVisible fallbackNull feature silently disappears
Text encodingNames retain accentsImport or font problem
Label densityCritical labels remain legibleOverlap or excessive repetition
Font availabilityServer uses approved fontDesktop font absent on server
TransparencyBasemap remains understandableFill opacity masks context
Cached outputLatest approved style appearsOld tiles survive style update

A QGIS style export can be a starting point, but do not promise one-to-one conversion of expressions, symbol layers or labeling rules. Test the exported result and record manual adjustments. Preserve both the original project and the server style so future changes can be traced.

Release and maintain the map

Store styles with the application configuration, use a distinct revision, and retain the preceding working version. Coordinate publication with GeoWebCache invalidation; a correct style does not immediately replace previously generated tiles. If a change alters category meaning, communicate that meaning in the legend and metadata rather than silently changing colors.

The useful deliverable is a small style package, fixed comparison requests, accepted images at three scales, font dependencies and documented exceptions. That is a maintainable migration result; a screenshot without its request parameters is difficult to reproduce.

Related articles