Sharing Data Artifacts with pins
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:
| Type | Function | Use case |
|---|---|---|
| RDS | writeRDS() | Any R object, R-only |
| CSV | write.csv() | Plain text, language-independent |
| Parquet | nanoparquet::write_parquet() | Large tabular data, efficient |
| JSON | jsonlite::write_json() | Nested structures |
| QS | qs2::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.