Skip to content

duckspatial

1.3.0Package record

R Interface to 'DuckDB' Database with Spatial Extension

4packages depend
28.6Kdownloads / year
90.1%test coverage
12/13flavors OK

Overview

About

Fast and memory-efficient functions to analyze and manipulate large spatial datasets. It leverages the fast analytical capabilities of ‘DuckDB’ and its spatial extension (see https://duckdb.org/docs/stable/core_extensions/spatial/overview) while maintaining compatibility with R’s spatial data ecosystem to work with spatial vector data.

Changes in 1.3.0

NEW FEATURES

  • Updated the duckdb dependency to v1.5.6. See <https://r.duckdb.org/news/index.html#duckdb-156>.
  • ddbs_expand(): expand the bounding box of geometries.
  • ddbs_default_conn(): creates or returns the default duckdb connection used internally by the package (#154).

PERFORMANCE

  • Less fixed overhead on every call with sf input: ddbs_register_table() no longer runs a call to register_geoarrow_extensions(), which does not exist in duckdb >= 1.5 and always failed (~45 ms per sf input), and building the DuckDB CRS literal skips a slow sf::st_crs(parameters = TRUE) lookup when the CRS has an EPSG code (~10 ms -> ~4 ms per call).

BUG FIXES

  • Functions called with sf or data.frame input no longer leak the registered data: each call left one Arrow registration (or a registered data.frame) and its memory in the connection until the session ended.
  • ddbs_write_table() is much faster: for sf input about 5x (1 million points: 6.3 s → 1.4 s, half the memory), and for a duckspatial_df or lazy table from the same connection about 100x (1 million rows: 5.4 s → 0.05 s), because the data no longer makes a round trip through R. ddbs_write_dataset() with sf input is about 2x faster.
  • ddbs_write_table() and ddbs_write_dataset() can now write sf objects that mix XYZ, XY and EMPTY geometries (previously "Skipping beyond end of binary data").
  • ddbs_write_table() now accepts a schema-qualified name as a single string (e.g. "s1.t"), and a failed write no longer leaves a partial table behind.
  • ddbs_filter(), the predicate functions with mode = "sf" (ddbs_intersects(), ddbs_within(), …) and the dense (sparse = FALSE) predicates in duckspatial mode now put the spatial predicate in a join condition, so DuckDB uses its spatial join instead of a cross product over every pair of features. On 100,000 points and the 100 nc counties, ddbs_filter() goes from about 14 s to about 1 s, ddbs_intersects(mode = "sf") from about 15 s to about 1 s and the dense duckspatial predicate from about 29 s to about 2 s. The sparse mode = "sf" result is built from the matching pairs only, so it no longer allocates an n × m matrix in R. Two consequences: ddbs_disjoint() cannot use the spatial join (nearly every pair matches) and is somewhat slower on large inputs; and in the dense mode = "sf" matrix, rows whose geometry is SQL NULL are now FALSE instead of NA.
Show all changes in 1.3.0Hide the rest of the changes in 1.3.0
  • Registering sf data in DuckDB is 3–4x faster and uses ~4x less memory (e.g. as_duckspatial_df() on 1 million points: 3.4 s → 0.8 s, 67 MB → 17 MB). This speeds up every ddbs_*() call with sf input. ddbs_register_table() no longer builds a chunk index for data that fits in a single Arrow chunk.
  • Every ddbs_*() call that uses the default connection is faster by about 50–100 ms: ddbs_default_conn() no longer re-creates the package's 35 SQL macros on each call. The macros are created once, when the connection is created. If you set the internal duckspatial_conn option to your own connection, run ddbs_load(conn) to create the macros on it.
  • as_duckspatial_df(), ddbs_register_table() and other functions that take an sf object no longer fail with "subscript out of bounds" on a 0-row sf. The result keeps the columns and the CRS.
  • sf data larger than ~500 MB (registered in several Arrow chunks) could only be read once: a second query or collect() on the same object returned 0 rows. It can now be read any number of times.
  • Fix nanoarrow::as_nanoarrow_array_stream(..., native = TRUE) to convert WKB geometry columns to native GeoArrow layouts such as geoarrow.point. Since the method was introduced, it had incorrectly returned geoarrow.wkb unchanged because its target schema was inferred from the existing WKB Arrow column (#121).
  • ddbs_filter() no longer drops rows of x that are exact duplicates of another row, and now returns the matching rows in their original order (#156).
  • ddbs_distance(), ddbs_azimuth() and the predicate functions (ddbs_predicate(), ddbs_intersects(), etc.) with mode = "sf" could return matrices with values in the wrong cells, because the cross join results were reshaped without an explicit row order (#155).
  • ddbs_* functions and print() now respect dplyr verbs that have no duckspatial_df method (e.g. distinct(), semi_join(), anti_join(), union_all()). Previously they silently used the original, unmodified table (#159).
  • ddbs_area(), ddbs_length(), ddbs_perimeter(), ddbs_distance() and the dwithin predicate (ddbs_is_within_distance(), ddbs_join(), ddbs_filter()) now compute planar results in the CRS's own units for projected CRSs not in metres (e.g. US survey feet), labelled as in sf; previously they returned NaN, mislabelled feet as metres, or found no dwithin matches. These functions and ddbs_buffer() now give an informative error when the input has no CRS, and WGS84 written as "OGC:CRS84" or "WGS 84" no longer triggers an accuracy warning (#161).
  • ddbs_read_meta() now gives an informative error for files GDAL can't open (e.g. GeoParquet) or that don't exist, instead of silently returning an empty tibble. ddbs_write_table() on a .parquet path no longer emits a spurious "Could not auto-detect CRS from file" warning before its error (#166).
  • ddbs_quadkey() no longer overwrites the input table when x is not in EPSG:4326, and now returns the correct quadkeys for such input. Previously, a table passed by name was replaced with lat/lon-swapped coordinates and no CRS, and all inputs returned wrong tiles (#164).
  • ddbs_contains() and ddbs_crosses() are now exported. They were documented but missing from the package namespace.
  • group_by() groups on a duckspatial_df are no longer lost after mutate(), filter(), arrange(), select() and other verbs. Previously a following summarise() silently collapsed all groups into a single row (#170).
  • Column, table and schema names that contain spaces or are SQL reserved words (e.g. a geometry column "my geom", by = "group", name = "my table", or a table named "order" passed as x) are now quoted in the generated SQL. Previously they failed with a parser error (#168).

From NEWS.md in the release

Install

Health

CRAN checks
1ERROR12OK
Check messages
ERRORre-building of vignette outputsr-devel-linux-x86_64-fedora-clang
Error(s) in re-building vignettes:
--- re-building ‘aw_interpolation.qmd’ using html
[31m

processing file: aw_interpolation.qmd
[39m[31mError in `value[[3L]]()`:
! Failed to load the spatial extension.
✖ DuckDB extension loading (INSTALL / LOAD) is disabled for this driver. ℹ
  Recreate the driver with duckdb(allow_extensions = TRUE) to enable it (this
  may crash R on a Linux build not compiled with libstdc++; see
  https://github.com/duckdb/duckdb-r/issues/1107). ℹ See ?duckdb for details. ℹ
  Context: load_extension
ℹ The binary may be corrupt or incompatible with this platform/DuckDB version.
ℹ Try reinstalling with `ddbs_install(extension = 'spatial', upgrade = TRUE)`
Backtrace:
     ▆
  1. └─duckspatial::ddbs_interpolate_aw(...)
  2.   └─duckspatial:::resolve_spatial_connections(...)
  3.     └─duckspatial::ddbs_default_conn()
  4.       └─duckspatial::ddbs_create_conn(dbdir = "memory", ...)
  5.         └─duckspatial::ddbs_load(conn, quiet = TRUE)
  6.           └─base::tryC
...[truncated]...
install(extension = 'spatial', upgrade = TRUE)`
  ---
  Backtrace:
  ▆
  1. └─duckspatial::ddbs_join(x = points_sf, y = countries_sf, join = "within")
  2.  └─duckspatial:::resolve_spatial_connections(...)
  3.  └─duckspatial::ddbs_default_conn()
  4.  └─duckspatial::ddbs_create_conn(dbdir = "memory", ...)
  5.  └─duckspatial::ddbs_load(conn, quiet = TRUE)
  6.  └─base::tryCatch(...)
  7.  └─base (local) tryCatchList(expr, classes, parentenv, handlers)
  8.  └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
  9.  └─value[[3L]](cond)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
  Execution halted
  [33mWARN: Error encountered when rendering files[39m
  
Caused by error in `processx::run()`:
! System command 'quarto' failed
--- failed re-building ‘spatial_joins.qmd’

SUMMARY: processing the following files failed:
  ‘aw_interpolation.qmd’ ‘duckspatial.qmd’ ‘spatial_joins.qmd’

Error: Vignette re-building failed.
Execution halted
ERRORtestsr-devel-linux-x86_64-fedora-clang
Running ‘testthat.R’
Running the tests in ‘tests/testthat.R’ failed.
Complete output:
  > # This file is part of the standard setup for testthat.
  > # It is recommended that you do not modify it.
  > #
  > # Where should you do additional test configuration?
  > # Learn more about the roles of various files in:
  > # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
  > # * https://testthat.r-lib.org/articles/special-files.html
  > 
  > library(testthat)
  > library(duckspatial)
  duckspatial 1.3.0 attached
  * Compatible with DuckDB >= v1.5.6
  
  Default output has changed on v1.0.0:
    duckspatial now returns lazy `duckspatial_df` (dbplyr) objects
    instead of `sf` objects.
  
  To restore the previous behaviour:
    ddbs_options(mode = 'sf')
  > library(duckdb)
  Loading required package: DBI
  > 
  > test_check("duckspatial")
  Reading layer `countries' from data source 
    `/data/localhost/ripley/R/packages/tests-clang/duckspatial.Rcheck/duckspatial/spatial/c
...[truncated]...
      └─base::eval(exprs, env)
   13.                       └─base::eval(exprs, env)
   14.                         ├─duckspatial::as_duckspatial_df(argentina_sf) at ./setup.R:15:1
   15.                         └─duckspatial:::as_duckspatial_df.sf(argentina_sf)
   16.                           └─duckspatial::ddbs_default_conn()
   17.                             └─duckspatial::ddbs_create_conn(dbdir = "memory", ...)
   18.                               └─duckspatial::ddbs_load(conn, quiet = TRUE)
   19.                                 └─base::tryCatch(...)
   20.                                   └─base (local) tryCatchList(expr, classes, parentenv, handlers)
   21.                                     └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
   22.                                       └─value[[3L]](cond)
   23.                                         └─cli::cli_abort(...)
   24.                                           └─rlang::abort(...)
  Execution halted

CRAN check page ↗

Slowest check: 4.7 min · r-oldrel-windows-x86_64
Status changes
  • ERROR12 OK, 1 ERRORNow
  • ERROR13 OK, 1 ERROR2026-03-10
Advisories

none known

Documentation

In release 1.3.0
READMEYes · 508 wordsVignettesYes · 4 · dynamicNEWSYes · 100% structured · mentions 1.3.0Citation fileNoWebsiteYes · pkgdown
Help pages
119 (25 internal)includes a package overview page
Examples that run
1%1 run in a plain check · 1 only when donttest examples are enabled (R CMD check --as-cran) · 86 never run
Exported functions with examples
89%
Documented parameters
100%
Return-value docs
100%
Help pages citing references
3%

Downloads

28.6K
CRAN downloads in the past year
Rank #1,680 · ~78/day · ~2.4K/mo
Daily download trend is not available in this view yet.
4.3K30 days
12.9K90 days
28.6K1 year
Compare downloads with other packages →
Also on442 r2u10 autocran

Repository

122Stars
5Forks
8Open issues
0Open PRs
10Releases
762Commits
4Commit identities
License file reads as GPL-3.0 · 762 commits · Last activity 2026-10-10 · +4.3% stars, 30d
Responsiveness
How these are sampled
PRs merged (all time)
94%
Median days to close, 50 most recently updated closed issues
12
Median days to close, 50 most recently updated closed PRs
2

Stars over time

2025-09-02 · 452026-10-12 · 122
PracticesBeta

12 development-tooling and community-health practices detected across 6 families in the upstream repository

Checks run against github.com/cidree/duckspatial on 2026-10-11.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel

Governance and community (1)
Funding

Funding links: buymeacoffee.com

Docs source (4)
README.Rmdpkgdown

GitHub Pages site last deployed 2026-10-11 · The repository has a site deploy workflow

pkgdown site last built 2026-10-11

Coverage (1)
Coverage reporting (Codecov)
Show all practicesHide 2 practices
CRAN release process (1)
cran-comments.md
Lint, format, editor (3)
AirVS CodeRStudio project
How this is detected·Detection ruleset v3 (2026-09-26)
AI coding toolsBeta

This repository shows signs of AI coding tools.

  • Claude Codefirst seen 2026-06-04
    Seen in the repository: .claude
    Named in .Rbuildignore: .claude
    Pull request it wrote: opened by a project member
    Commits: at least 35 crediting it in the message
Models named in its commits
  • Claude Sonnet 4.616 commits · Jun 2026
  • Claude Opus 4.811 commits · Jun 2026
  • Claude Opus 5.58 commits · Oct 2026
Counts are commits, not lines of code. Commits by a tool's accounts count once across all of its accounts. Commits crediting it are the largest count among its credit lines, a minimum.How this is detected·Detection ruleset v4 (updated 2026-09-27)

Dependencies

Declared dependencies
32 external dependencies (excludes base and recommended)

Installing duckspatial adds 40 packages (28 with compiled code, 46 MB of source tarballs). Heaviest: stringi 11 MB, sf 9.3 MB, duckdb 4.6 MB.

Depends (1)
R >= 4.1.0
LinkingTo (0)
none
Enhances (0)
none
Reverse dependencies
4direct
0indirect
Imports 4
Depends, Imports or LinkingTo, most downloaded first

People & History

People (3)
Author, Maintainer since 0.1.0 (2025)
Author · added in 0.9.0
Author · added in 0.9.0
Releases (10)

Pick two releases to compare their code metrics.

  • 1.3.0Latest
    record
    2026-07-04 · current release · diff ↗ ·
    added 4 exports
    ddbs_contains, ddbs_crosses, ddbs_default_conn, ddbs_expand
  • 1.2.1
    record
    2026-07-04 · diff ↗
  • 1.2.0
    record
    2026-06-22 · diff ↗ ·
    added 14 exports
    ddbs_as_mvt_geom, ddbs_extension_info, ddbs_geom_from_geojson, ddbs_geom_from_hexewkb, ddbs_geom_from_hexwkb, ddbs_geom_from_text, ddbs_geom_from_wkb, ddbs_get_ninterior_rings, ddbs_intersection_agg, ddbs_line_node, ddbs_normalize, ddbs_reduce_precision, ddbs_reverse, ddbs_write_mbtiles
  • 1.1.2
    record
    2026-06-22 · diff ↗ ·
    added 14 exports
    ddbs_azimuth, ddbs_dimension, ddbs_line_locate_point, ddbs_mmax, ddbs_mmin, ddbs_point, ddbs_shortest_line, ddbs_vertices, ddbs_xmax, ddbs_xmin, ddbs_ymax, ddbs_ymin, ddbs_zmax, ddbs_zmin
  • 1.1.1
    record
    2026-06-06 · diff ↗ ·
    added 3 exports
    ddbs_affine, ddbs_get_ngeometries, ddbs_get_npoints
  • 1.1.0
    record
    2026-05-17 · diff ↗ ·
    added 18 exports
    ddbs_crop, ddbs_dump, ddbs_line_endpoint, ddbs_line_interpolate, ddbs_line_merge, ddbs_line_startpoint, ddbs_line_substring, ddbs_locate_along, ddbs_locate_between, ddbs_m, ddbs_make_envelope, ddbs_make_line, ddbs_maximum_inscribed_circle, ddbs_minimum_rotated_rectangle, ddbs_read_meta, ddbs_remove_repeated_points, ddbs_set_crs, ddbs_z
  • R
    R 4.6.0 released · 2026-04-24
  • 1.0.0
    record
    2026-03-30 · diff ↗ ·
    removed 2 exports
    ddbs_contains, ddbs_crosses
    added 38 exports
    as_duckspatial_df, ddbs_as_geojson, ddbs_as_points, ddbs_build_area, ddbs_collect, ddbs_compute, ddbs_drop_geometry, ddbs_endpoint, ddbs_flip_coordinates, ddbs_force_2d, ddbs_force_3d, ddbs_force_4d, ddbs_geom_col, ddbs_geometry_type, ddbs_get_resources, ddbs_has_m, ddbs_has_z, ddbs_is_closed, ddbs_is_empty, ddbs_is_ring, ddbs_multi, ddbs_open_dataset, ddbs_options, ddbs_perimeter, ddbs_polygonize, ddbs_read_table, ddbs_register_table, ddbs_set_resources, ddbs_sitrep, ddbs_startpoint and 8 more
  • 0.9.0
    record
    2026-01-10 · diff ↗ ·
    added 49 exports
    ddbs_area, ddbs_as_hexwkb, ddbs_as_text, ddbs_as_wkb, ddbs_bbox, ddbs_boundary, ddbs_combine, ddbs_concave_hull, ddbs_contains, ddbs_contains_properly, ddbs_convex_hull, ddbs_covered_by, ddbs_covers, ddbs_create_conn, ddbs_crosses, ddbs_disjoint, ddbs_distance, ddbs_drivers, ddbs_envelope, ddbs_equals, ddbs_exterior_ring, ddbs_flip, ddbs_generate_points, ddbs_interpolate_aw, ddbs_intersects, ddbs_intersects_extent, ddbs_is_simple, ddbs_is_valid, ddbs_is_within_distance, ddbs_join and 19 more
  • 0.2.0
    record
    2025-04-29 · diff ↗ ·
    added 5 exports
    ddbs_buffer, ddbs_centroid, ddbs_difference, ddbs_glimpse, ddbs_list_tables
  • 0.1.0
    record
    2025-04-19
  • R
    R 4.5.0 released · 2025-04-11

Package metadata

First published
2025-04-19
Total releases
10 / 1 yrs
License
GPL (>= 3) OSI
Minimum R
≥ 4.1.0
Download size
4.7 MB
Appears in task views

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("duckspatial")
Cidre González, A., Kotov, E., & Pereira, R. H. M. (2026). duckspatial: R Interface to 'DuckDB' Database with Spatial Extension (Version 1.3.0) [Computer software]. https://doi.org/10.32614/CRAN.package.duckspatial

This package has no citation file, so citation() returns this entry built from DESCRIPTION.

Cite the R Observatory

For a number measured here: a download total, a coverage figure, an archival date.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for duckspatial version 1.3.0 [Data set]. HJJB, LLC. Data release v2026-10-18. https://doi.org/10.5281/zenodo.21843040

From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy