Warning - This site is under development. Some features may not work as expected.

duckspatial v0.9.0

R
spatial
duckspatial
New duckspatial version. A major step towards v1.0.0
Author

Adrián Cidre

Published

January 10, 2026

1 Introduction

I’m exited to announce the release of {duckspatial} v0.9.0 () , now available ON CRAN! This new version brings a major evolution of the package, with substantial changes that make the way towards version 1.0.0.

2 What is duckspatial?

For those new to the package, {duckspatial} brings the power of DuckDB’s spatial extension to R. It provides fast and memory-efficient functions to analyze and manipulate large spatial vector datasets while maintaining full compatibility with R’s spatial ecosystem, especially the {sf} package ().

The package is designed for situations where:

  • You’re working with large spatial datasets

  • You need to speed up spatial analysis at scale

  • Your data doesn’t fit in memory

3 Major changes in 0.9.0

If you’ve used {duckspatial} before, you might ask why did we jump from version 0.2.0 to version 0.9.0, instead of 0.3.0 or 1.0.0. Well, this new release brings substantial changes, some of them might have incompatibilities with the previous version. However, we are reserving the v1.0.0 for the next release that we are working in, which will bring fantastic news, such as lazy duckspatial tables, and native support of Coordinates Reference Systems (CRS) within DuckDB (see this issue for a reference). In this sense, to we decided that moving to 0.3.0 wasn’t enough for the big changes this versions brings, and we think version 1.0.0 should be released with the previously mentioned roadmap. So now that we know why this is v0.9.0, let’s dive into the major changes.

3.1 Simplified connection handling

The biggest change in this release is how the connections are handled. The conn argument now defaults to NULL in every spatial operation (e.g. ddbs_centroid, ddbs_filter, ddbs_area, …), and it’s no longer a mandatory argument. This means that the package will handle internally the connection if the user prefer to work with {sf} objects instead of DuckDB tables, making the package more user friendly. The next examples show how to calculate the centroid using a connection, or without using a connection.

NOTE: The first time you use one function from {duckspatial}, it will run internally ddbs_install() and ddbs_load() to set up the spatial extension, and it will take slightly longer. After the first time, everything will go faster.

## load packages
library(duckspatial)
library(sf)

## load Argentina boundaries as sf
argentina_sf <- read_sf(system.file("spatial/argentina.geojson", package = "duckspatial"))

## get centroid
argentina_centroid_sf <- ddbs_centroid(argentina_sf)
argentina_centroid_sf
Simple feature collection with 1 feature and 6 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -65.14851 ymin: -35.20212 xmax: -65.14851 ymax: -35.20212
Geodetic CRS:  WGS 84
  CNTR_ID NAME_ENGL ISO3_CODE CNTR_NAME FID       date
1      AR Argentina       ARG Argentina  AR 2021-01-01
                     geometry
1 POINT (-65.14851 -35.20212)
## load packages
library(duckspatial)
library(sf)

## create a connection (in memory)
## NOTE: ddbs_create_conn() is a wrapper of dbConnect(), ddbs_install(), and ddbs_load()
conn <- ddbs_create_conn()

## load Argentina boundaries as sf
argentina_sf <- read_sf(system.file("spatial/argentina.geojson", package = "duckspatial"))

## get centroid
argentina_centroid_sf <- ddbs_centroid(argentina_sf, conn)
argentina_centroid_sf
Simple feature collection with 1 feature and 6 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -65.14851 ymin: -35.20212 xmax: -65.14851 ymax: -35.20212
Geodetic CRS:  WGS 84
  CNTR_ID NAME_ENGL ISO3_CODE CNTR_NAME FID       date
1      AR Argentina       ARG Argentina  AR 2021-01-01
                     geometry
1 POINT (-65.14851 -35.20212)

This change makes {duckspatial} feel more natural for {sf} users while still offering the flexibility to work with existing DuckDB connections when needed.

3.2 Flexible Input/Output

All spatial functions now support four workflows:

  • Input sf → Output sf

  • Input sf → Output DuckDB table

  • Input DuckDB table → Output sf

  • Input DuckDB table → Output DuckDB table

This flexibility lets you choose the right approach for your data size and workflow. Note that working inside DuckDB without pulling the data into R’s memory will be much more efficient, but it will be different than an {sf} workflow.

argentina_centroid_sf <- ddbs_centroid(argentina_sf)
## write data into the connection
ddbs_write_vector(conn, argentina_centroid_sf, name = "argentina")

## input duckdb table, output sf
argentina_centroid_sf <- ddbs_centroid("argentina", conn)
ddbs_centroid(argentina_sf, conn, name = "argentina_centroid")
ddbs_centroid("argentina", conn, name = "argentina_centroid", overwrite = TRUE)

3.3 Performance Improvements

Two key optimizations make this release significantly faster:

3.4 CRS Deprecation

The crs and crs_column arguments are now deprecated and will be removed in version 1.0.0. This change aligns with native CRS support coming to DuckDB v1.5.0 (expected February 2026). The package will handle coordinate reference systems more seamlessly once DuckDB’s native support is available.

4 New Features

This release adds a substantial number of new spatial functions, greatly expanding what you can do with {duckspatial}. Particularly, it brings more than 30 new functions!! 🚀

4.1 Geometric Operations

4.2 Spatial Analysis

4.3 Coordinate Transformations and Format Conversions

4.4 Utility Functions

5 Minor improvements

  • All functions now have a quiet parameter to suppress messages
  • Fixed issue where columns with dots in their names would cause failures
  • Improved ddbs_filter() to avoid duplicates when geometries match multiple predicates
  • Added comprehensive vignettes for getting started

6 Looking Ahead to 1.0.0

Version 0.9.0 sets the stage for the 1.0.0 release, which will bring additional substantial changes. The upcoming release will fully integrate DuckDB’s native CRS support and lazy duckspatial tables.

7 Acknowledgments

This release wouldn’t be possible without the incredible work of many people.

First and foremost, my deepest thanks to the DuckDB team for building such a powerful and elegant analytical engine. Their commitment to performance, correctness, and developer experience has created a foundation that makes tools like {duckspatial} possible.

Special recognition goes to the developers of the DuckDB Spatial Extension, the engine that powers everything in {duckspatial}. Their unvaluable work on spatial operations, format support, and performance optimization is what makes this package capable of handling large-scale spatial analysis efficiently.

Most importantly, this release represents a true collaborative effort. Rafael Pereira and Egor Kotov have been fundamental in shaping duckspatial’s new design and implementation. Their ideas, code contributions, and thoughtful feedback have shaped this package far beyond what I could have achieved alone. This is a shared accomplishment.

Finally, thank you to the broader R spatial community for building the ecosystem that {duckspatial} integrates with, and to everyone who has tested early versions, reported issues, or provided feedback.

8 References

Cidre González, Adrián, Rafael H. M. Pereira, and Egor Kotov. 2026. “Duckspatial: R Interface to ’DuckDB’ Database with Spatial Extension.” https://github.com/Cidree/duckspatial.
Dunnington, Dewey. 2025. “Geoarrow: Extension Types for Spatial Data for Use with ’Arrow’.” https://doi.org/10.32614/CRAN.package.geoarrow.
Dunnington, Dewey, and Edzer Pebesma. 2025. Wk: Lightweight Well-Known Geometry Parsing. https://doi.org/10.32614/CRAN.package.wk.
Pebesma, Edzer, and Roger Bivand. 2023. Spatial Data Science: With Applications in r.” https://doi.org/10.1201/9780429459016.