R/storage-config.R

Defines functions print.duckdb_storage_status duckdb_storage_status duckdb_secret_storage duckdb_extension_storage

Documented in duckdb_extension_storage duckdb_secret_storage duckdb_storage_status

# Documentation and implementation for the user-facing functions that configure
# where the duckdb R package stores extensions and secrets. The storage policy
# itself is described in `?duckdb_storage`. See `?duckdb_storage_config`.

#' Configure where DuckDB stores extensions and secrets
#'
#' @description
#' `r lifecycle::badge('experimental')`
#'
#' Choose where the duckdb R package keeps downloaded extensions and persisted
#' secrets, by writing a small marker file that records the choice:
#'
#' * `duckdb_extension_storage()` -- set or move the extension cache (default: a
#'   per-session temporary directory).
#' * `duckdb_secret_storage()` -- set or move the secret store (default: a
#'   per-session temporary directory).
#' * `duckdb_storage_status()` -- report where each currently resolves.
#'
#' These functions move the cache and secret store to a location that survives
#' across sessions; the same locations can also be set without a marker by
#' overriding with options and environment variables. The full policy is
#' documented in [duckdb_storage].
#'
#' @details
#' `duckdb_extension_storage()` and `duckdb_secret_storage()` write (or remove)
#' the marker for that one kind of state, so the two can be configured
#' independently. `duckdb_storage_status()` reports where each kind currently
#' resolves and which tier of the resolution policy chose it. The new location
#' takes effect for connections opened afterwards; existing connections are
#' unaffected.
#'
#' There is no `ask` argument: calling a `*_storage()` function is itself the
#' consent to write outside the temporary directory.
#'
#' @param location The destination root (not a path), one of:
#'   * `"session"` -- the per-session temporary directory; the default, and the
#'     opt-out (removes the marker, reverting to a per-session location).
#'   * `"user"` -- [tools::R_user_dir()].
#'   * `"shared"` -- `~/.duckdb`, shared with the DuckDB CLI and Python client.
#'
#'   To use an arbitrary directory, set the option or environment variable
#'   instead (see [duckdb_storage]).
#' @inheritParams rlang::args_dots_empty
#' @param migrate If `TRUE` (the default), move the already-cached files from the
#'   current location into the new one. Ignored when `location` is `"session"`:
#'   opting out never moves files into the per-session directory.
#' @param conflict How to resolve a name collision during migration: `"error"`
#'   (the default) aborts and lists the collisions without moving anything;
#'   `"ours"` lets the files being relocated overwrite the destination;
#'   `"theirs"` keeps the destination files and drops the colliding sources.
#'
#' @return The `*_storage()` functions are called for their side effect (writing
#'   or removing a marker, and optionally migrating files) and return the
#'   resolved directory invisibly. `duckdb_storage_status()` returns a data frame
#'   (class `"duckdb_storage_status"`) with one row per kind of state and columns
#'   `kind`, `source`, and `directory`; its print method renders a readable
#'   summary when the result is auto-printed.
#'
#' @seealso [duckdb_storage] for the storage policy these functions implement.
#' @name duckdb_storage_config
NULL

#' @rdname duckdb_storage_config
#' @export
duckdb_extension_storage <- function(
  location = c("session", "user", "shared"),
  ...,
  migrate = TRUE,
  conflict = "error"
) {
  check_dots_empty0(...)
  location <- arg_match(location)
  set_storage_marker("extensions", location, migrate, conflict)
}

#' @rdname duckdb_storage_config
#' @export
duckdb_secret_storage <- function(
  location = c("session", "user", "shared"),
  ...,
  migrate = TRUE,
  conflict = "error"
) {
  check_dots_empty0(...)
  location <- arg_match(location)
  set_storage_marker("stored_secrets", location, migrate, conflict)
}

#' @rdname duckdb_storage_config
#' @export
duckdb_storage_status <- function() {
  extensions <- describe_storage("extensions")
  stored_secrets <- describe_storage("stored_secrets")
  status <- data.frame(
    kind = c("extensions", "stored_secrets"),
    source = c(extensions$source, stored_secrets$source),
    directory = c(extensions$directory, stored_secrets$directory),
    stringsAsFactors = FALSE
  )
  class(status) <- c("duckdb_storage_status", "data.frame")
  # Returned visibly: the print method below renders the readable summary when
  # the result is auto-printed, while assignment stays quiet as usual.
  status
}

#' @export
print.duckdb_storage_status <- function(x, ...) {
  cat("DuckDB storage locations:\n")
  kind <- format(x$kind, width = max(nchar(x$kind)))
  source <- format(
    paste0("[", x$source, "]"),
    width = max(nchar(x$source)) + 2L
  )
  cat(paste0("  ", kind, "  ", source, "  ", x$directory), sep = "\n")
  invisible(x)
}

Try the duckdb package in your browser

Any scripts or data that you put into this service are public.

duckdb documentation built on July 10, 2026, 5:08 p.m.