GeoJSON to Simple Feature Converter

Converts Between GeoJSON and simple feature objects.

CRAN_Status_Badge downloads CRAN RStudio mirrordownloads GithubStars BuildStatus CoverageStatus

A simple, low-dependency and fast converter between GeoJSON and Simple Feature objects in R.



  • GeoJSON –> sf
  • GeoJSON –> sfc
  • sf –> GeoJSON
  • sfc –> GeoJSON
  • GeoJSON –> Well-known text
  • data.frame –> GeoJSON (POINT only)

As per GeoJSON (RFC 7946 specification), foreign members are ignored, and nested objects and arrays inside the properties object are converted to string/characters.


Install the CRAN version with


To install the development version

# install.packages("devtools")

Why did you build it?

To quickly parse between GeoJSON and sf objects, and to handle cases not supported by sf, e.g. arrays of geometries

What do you mean, ‘cases not supported’

For example, sf can’t read an array of GeoJSON objects, so I wanted to make this work

js <- c(
      "type": "FeatureCollection",
      "features": [
        "type": "Feature",
        "properties": {"id":1},
        "geometry": {"type": "Point", "coordinates": [100.0, 0.0]}
sf <- geojson_sf( js )
#  Simple feature collection with 3 features and 1 field
#  geometry type:  GEOMETRY
#  dimension:      XY
#  bbox:           xmin: -1 ymin: -1 xmax: 100 ymax: 1
#  epsg (SRID):    4326
#  proj4string:    +proj=longlat +datum=WGS84 +no_defs
#    id                geometry
#  1 NA             POINT (0 0)
#  2 NA LINESTRING (-1 -1, 1 1)
#  3  1           POINT (100 0)

And going the other way you can also return a vector of GeoJSON

js <- sf_geojson( sf, atomise = T )
#  {"type":"Feature","properties":{"id":null},"geometry":{"type":"Point","coordinates":[0.0,0.0]}} 
#  {"type":"Feature","properties":{"id":null},"geometry":{"type":"LineString","coordinates":[[-1.0,-1.0],[1.0,1.0]]}} 
#  {"type":"Feature","properties":{"id":1.0},"geometry":{"type":"Point","coordinates":[100.0,0.0]}}

What’s the benefit of ‘atomising’?

It’s useful for when you work with geospatial databases and want an individual record for each individual feature.

What happens if you don’t atomise?

You get a single GeoJSON object

sf_geojson( sf )
#  {"type":"FeatureCollection","features":[{"type":"Feature","properties":{"id":null},"geometry":{"type":"Point","coordinates":[0.0,0.0]}},{"type":"Feature","properties":{"id":null},"geometry":{"type":"LineString","coordinates":[[-1.0,-1.0],[1.0,1.0]]}},{"type":"Feature","properties":{"id":1.0},"geometry":{"type":"Point","coordinates":[100.0,0.0]}}]}

Can you remove the properites and just return the geometries

Yes. Call sfc_geojson() on the sfc object.

sfc_geojson( sf$geometry )
#  {"type":"Point","coordinates":[0.0,0.0]} 
#  {"type":"LineString","coordinates":[[-1.0,-1.0],[1.0,1.0]]} 
#  {"type":"Point","coordinates":[100.0,0.0]}

If I have an sf object without any properties, why does it ‘atomise’ by default?

sf$id <- NULL
sf_geojson( sf )
#  {"type":"Point","coordinates":[0.0,0.0]} 
#  {"type":"LineString","coordinates":[[-1.0,-1.0],[1.0,1.0]]} 
#  {"type":"Point","coordinates":[100.0,0.0]}

The simplify argument is TRUE by default, and it will try and ‘simplify’ the GeoJSON. If there are no properties in the sf object, then the GeoJSON won’t have any properties.

However, if you set simplify = FALSE you’ll get a FeatureCollection with an empty properties field.

sf_geojson(sf, simplify = F)
#  {"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[0.0,0.0]}},{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-1.0,-1.0],[1.0,1.0]]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[100.0,0.0]}}]}

How fast is it?

This benchmark shows a comparison with library(sf) for converting a string of GeoJSON of 3,221 counties in the US in to an sf object

myurl <- ""
geo <- readLines(myurl)
geo <- paste0(geo, collapse = "")
    geojsonsf = {
    sf = {
        sf::st_read(geo, quiet = T)
    times = 2
#  Unit: milliseconds
#        expr       min        lq      mean    median        uq       max
#   geojsonsf  709.2268  709.2268  722.0626  722.0626  734.8984  734.8984
#          sf 1867.6840 1867.6840 1958.7968 1958.7968 2049.9097 2049.9097
#   neval
#       2
#       2

Does it work?

I’ve written a lot of tests to try and capture all eventualities. But if you find a mistake please let me know.

Here’s a quick visual check to see the output of the above benchmark data

gsf <- geojson_sf(geo)
google_map() %>%
    add_polygons(gsf[!gsf$STATE %in% c("02","15","72"), ], 
            fill_colour = "CENSUSAREA", 
            stroke_weight = 0)
sf <- sf::st_read(geo, quiet = T)
plot(st_geometry(sf[!sf$STATE %in% c("02", "15", "72"), ]))



  • restructured C++ src code for easier navigation and linking
  • added dependency on jsonify v0.2 and fixed tests
  • Factors now default to strings


  • digits argument for rounding coordinates
  • fix '{"type":"FeatureCollection","features":[]}' example Issue 58


  • fixed crash when mis-specified MultiPolygon issue 51
  • df_geojson() converts data.frame to GeoJSON POINTs


  • sf_geojson() and sfc_geojson() output "json" class objects
  • better handling of null objects / geometries issue 36
  • Date and POSIX objects handled issue 32
  • Z (elevation) and M attributes handled issue 28
  • simplify argument for geojson_sf() to keep FeatureCollections when converting sf without properties
  • sf_geojson() performance improvments using jsonify


  • factors are now treated as-is (numeric)



  • sf_geojson() and sfc_geojson() to convert from sf to GeoJSON
  • geojson_sf() and geojson_sfc() can now read from a url or file

v0.2.0 First release

  • geojson_sf() convert GeoJSON to sf object
  • geojson_sfc() convert GeoJSON to sfc object
  • geojson_wkt() convert GeoJSON to data.frame with a Well-known text column

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.


2.0.1 by David Cooley, a year ago

Report a bug at

Browse source code at

Authors: David Cooley [aut, cre]

Documentation:   PDF Manual  

MIT + file LICENSE license

Imports Rcpp

Suggests covr, jsonify, knitr, rmarkdown, tinytest

Linking to geometries, jsonify, rapidjsonr, Rcpp, sfheaders

System requirements: C++11

Imported by RtD3, TargomoR, echor, geojsonio, giscoR, leafem, leafgl, mapboxapi, mapboxer, mapdeck, otpr, spectator.

Suggested by cancensus, graphhopper, leaflet.extras2, openeo, spatialwidget, stats19, tongfen, ursa.

See at CRAN