Sharing Data Artifacts with pins

· 2 min read · Updated March 17, 2026 · intermediate
r data pins r-packages

The pins package helps you share data, models, and other R objects across projects and with colleagues. Rather than emailing datasets or copying files manually, you “pin” objects to a board—a storage location that makes them easily discoverable and retrievable.

Boards

Every pin lives in a pin board. Create a board based on how you want to share data:

library(pins)

# Local storage (same computer, different R sessions)
board <- board_local()

# Shared folder (Dropbox, network drive)
board <- board_folder("~/Dropbox")

# Posit Connect
board <- board_connect()

# Amazon S3
board <- board_s3("my-bucket")

# Azure Blob Storage
board <- board_azure(container = "my-container")

For testing, board_temp() creates a temporary board that disappears when your R session ends.

Writing and Reading Pins

Once you have a board, writing data is straightforward:

board |> pin_write(mtcars, "mtcars-dataset")

The first argument is your R object (usually a data frame), and the second is the pin name. Pin names cannot contain slashes.

Reading it back is equally simple:

retrieved <- board |> pin_read("mtcars-dataset")

You don’t need to specify the file type when reading—pins stores that information automatically in the metadata.

File Types

Pins automatically detects how to save your data, but you can specify different formats:

TypeFunctionUse case
RDSwriteRDS()Any R object, R-only
CSVwrite.csv()Plain text, language-independent
Parquetnanoparquet::write_parquet()Large tabular data, efficient
JSONjsonlite::write_json()Nested structures
QSqs2::qs_save()Fast binary, large objects
board |> pin_write(df, "my-data", type = "parquet")

Avoid pinning files over 500 MB—pins transmits over HTTP, which becomes slow and unreliable for very large files.

Metadata

Every pin stores metadata automatically. Access it with pin_meta():

board |> pin_meta("mtcars-dataset")

This returns information about file size, hash, creation date, and type. You can also add custom metadata:

board |> pin_write(df, "analysis", 
  metadata = list(owner = "data-team", version = "1.0"))

Add tags for organization:

board |> pin_write(df, "dataset", tags = c("production", "daily"))

Versioning

Enable versioning to keep a history of changes:

board <- board_local(versioned = TRUE)
board |> pin_write(v1, "model")
board |> pin_write(v2, "model")  # Creates new version, keeps v1

List all versions:

board |> pin_versions("model")

Read a specific version:

board |> pin_read("model", version = "20250115T103000Z-abc123")

Delete old versions with pin_version_delete() or pin_versions_prune().

When to Use Pins

Pins works well when a single process writes data that multiple processes read:

  • ETL pipelines storing daily model outputs
  • Shared reference datasets across projects
  • Caching remote data locally

Pins is not designed for concurrent writes. Don’t use it for Shiny apps where multiple users write simultaneously—the package can’t manage conflicts.

Finding Pins

Use pin_search() to discover pins on a board:

board |> pin_search("model")

This searches pin names, titles, descriptions, and tags.