Tom MacWright

tom@macwright.com

Everything you need to know now about RFC 7946 GeoJSON

GeoJSON is a great, simple format that has been implemented in tons of software and is one of the most common formats for spatial vector data. The standard was first created ad-hoc - not under an organization like the IETF or OGC, but as a collaborative project led by a few smart individuals.

Recently, those authors re-formed along with new supporters and put GeoJSON through the IETF standardization process, yielding a stamped-and-approved international standard with a number: RFC 7946.

First, a word about change

As Sean makes clear, it’s not GeoJSON 2.0 - it’s GeoJSON, or if you need to be specific, “RFC 7946 GeoJSON”.

Image of the rates of change of formats, standards, and languages

Formats change slowly and painfully. Languages change at a moderate pace. Software can change quickly with relatively minimal fuss.

This is a good thing. We - people who use and create technology - should understand a natural change layering between formats, languages, and software. Formats, like GeoJSON, JSON, and XML, change extremely slowly, and often not at all. Since Douglas Crockford proposed JSON in the early 2000s, there have been virtually no changes to the language.

Likewise, the RFC 7946 GeoJSON doesn’t introduce any whiz-bang new features. It doesn’t try to make GeoJSON into a binary representation, or introduce topology or curves. If you’ve read the GeoJSON specification often (that may just be me), the new specification will sound very familiar. Most of the changes are clarifying up GeoJSON features that were defined ambiguously. A few changes remove GeoJSON features that were rarely implemented and made the format more complex.

If you pay attention to internet formats, you’ll notice a winning strategy: try to nail it on the first try. Or, potentially try to nail it before the thing gets famous. Unfortunately, that isn’t easy advice to implement, but it’s a ‘win theme’ as an MBA might say.

Luckily, GeoJSON nailed the fundamentals on the first try, and the IETF is unlikely to cause much pain for implementors - most GeoJSON will stay valid in the new specification.1

The crs member was removed

Projected GeoJSON files were valid before, but now all GeoJSON files must be in the WGS84 datum.

Map projections are different ways of portraying the Earth, a bumpy 3D ball, on flat surfaces. Cartographers love, study, and defend map projections.

Projected data, a connected but separate topic, is when people store data itself in projected units - instead of longitude and latitude, they might store meters or feet, or some other local unit. Traditionally, most data was stored in local units, because moving data between projections was slow and imprecise.

GeoJSON previously allowed for data to be stored in custom projections, but as of the IETF standard, it requires all data to be stored as WGS84 - in longitude and latitude, in the same style as GPS data.

For most users, this is a good thing: in the rare occasion you encountered a projected GeoJSON file, you’d have to reproject the file yourself using a system like proj4, and hope that your local computer has the projection definitions you want. Or, more likely, the GeoJSON-implementing software you’re relying on won’t support projections and will assume that the file is in WGS84.

For the majority of users and use-cases, the removal of data projections in GeoJSON is a win, because it eliminates a rare form of GeoJSON that had little support in implementations.

Position arrays should not be extended beyond 3 members

GeoJSON position arrays are now either [longitude, latitude], or [longitude, latitude, altitude]. Previously, GeoJSON let these position arrays extend beyond altitude: you could add more dimensions, but, like longitude, latitude, and altitude, those dimensions would have to be expressed numerically.

This meant, that you might add a time dimension - or anything else - to position arrays, but only in a limited way with numbers, and implementations weren’t guaranteed to honor or understand the meaning of the addition.

Positions with extra non-spatial data do exist in a handful of formats, including OSM XML and GPX. I proposed geojson-coordinate-properties as a way to stash this kind of data in properties instead.

id must be a string or a number

It’s easier to index GeoJSON features in a hash table because the specification requires that the keys are simple.

The id member of Feature objects is often neglected in implementations, and I often see GeoJSON files that put unique identifiers in properties instead of id, which is unfortunate.

Why use the id member? Often we store GeoJSON features in a hash table to make feature lookup fast and easy.

This use-case explains the newly strict type of the id member: when GeoJSON didn’t specify the type of id, you could set a Feature’s id member to an object or array. The vast majority of hash tables only allow indexing by primitive types like strings and numbers. Indexing a hash table with objects and arrays is usually inefficient or impossible.

GeoJSON objects must not contain defining members of other types

Adding a ‘properties’ member to a FeatureCollection would be confusing for you, and making this rule makes it easier for streaming GeoJSON parsers to decide what type they’re currently looking at.

The types of GeoJSON objects are defined by the type member: this member will say, simply, Polygon, for a polygon, or Feature, for a feature. Reading the type member is a fail-proof way of parsing GeoJSON types, but it can be inefficient for parsing gigantic GeoJSON files: a FeatureCollection might have gigabytes of data before the type member. In that case, it’s helpful to treat the presence of a features member as proof of an object being a FeatureCollection.

This is a useful trick, but before the IETF standard, people were allowed to add specified members from some GeoJSON object types to other object types - chimeric objects like Polygon geometries with features members, or a FeatureCollection with a coordinates member - wreaking havoc on any parser that tries to guess types. Now that’s forbidden by the standard.

And some more minor changes

If no altitude is provided, implementations should assume it’s zero

GeoJSON represents ‘no altitude’ as undefined, instead of 0. This saves valuable bytes, but until the IETF draft it was up to interpretation, whether omitted altitude might be zero or ground level, or something else.

The values for a bbox array must be in “[west, south, east, north]”, not “[minx, miny, maxx, maxy]”

This clears up a point of confusion with features that cross the 180th meridian. Previously, when the bbox was defined as minx and maxx, features that spanned the meridian were left in the awkward situation of having a west side of, say, 170 longitude, and east of -170 longitude. The standard cleared up the semantic meaning of bounding boxes to fix the case where the minimum and maximum numbers are not the west and east sides.

On the same topic, the IETF standard recommends that polygon rings follow the right-hand-rule for orientation. This makes it clear which way polygons wrap when they cross the 180th meridian. Plus, it’s slightly easier to render polygons and calculate their areas.

Extensions may be used, but must not change the semantics of GeoJSON members and types

Meaning, simply, extensions need to build on GeoJSON’s statements but can’t change them: you shouldn’t add some new member to a LineString that causes software to interpret it as a Polygon instead.

The specification recommends limiting coordinate precision to 6

With 6 decimal digits, you can specify any location on Earth to a tolerance of 10 centimeters, which is below GPS’s and probably much more accurate than you need. The GeoJSON specification now recommends that you keep coordinates down to 6 decimal places: but importantly this is a recommendation and not a requirement. geojsonhint lets you test for this with the coordinatePrecision rule, and you can enforce precision by using a method like toFixed.


Notes

  1. And, if you need to check, I’d recommend geojsonhint, which now validates according to the IETF spec.