Skip to content
A Data Mapper library to enable multiple backends for storage of files and metadata in Samvera
Branch: master
Clone or download
tpendragon Merge pull request #700 from samvera/readme_badge
Switch README from samvera-labs to samvera
Latest commit b0fe286 Mar 19, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.docker-stack Update docker-compose. Jan 7, 2019
bin Add rspec binstub. Feb 28, 2018
db Optimistic locking for Postgres Aug 3, 2018
solr Use Appraisal to test all supported versions. Mar 19, 2019
.gitignore Use Appraisal to test all supported versions. Mar 19, 2019
.tool-versions Use Appraisal to test all supported versions. Mar 19, 2019
Appraisals Use Appraisal to test all supported versions. Mar 19, 2019 Release 1.5.1 Feb 8, 2019
Gemfile Remove the MVP app. Fixes #314 Nov 15, 2017
LICENSE Switch README from samvera-labs to samvera Mar 19, 2019
Rakefile Use Appraisal to test all supported versions. Mar 19, 2019
browserslist Initial rails generation Aug 26, 2016
valkyrie.gemspec Use Appraisal to test all supported versions. Mar 19, 2019


Valkyrie is a gem for enabling multiple backends for storage of files and metadata in Samvera.

Valkyrie Logo

Code: Version Build Status Coverage Status

Docs: Contribution Guidelines Apache 2.0 License Yard Docs

Jump in: Slack Status

Primary Contacts

Product Owner

Carolyn Cole

Technical Lead

Trey Pendragon


The Samvera community is here to help. Please see our support guide.

Getting Started

Add this line to your application's Gemfile:

gem 'valkyrie'

And then execute:

$ bundle


Valkyrie is configured in two places: an initializer that registers the persistence options and a YAML configuration file that sets which options are used by default in which environments.

Sample initializer: config/initializers/valkyrie.rb:

Here is a sample initializer that registers a couple adapters and storage adapters, in each case linking an instance with a short name that can be used to refer to it in your application:

# frozen_string_literal: true
require 'valkyrie'
Rails.application.config.to_prepare do


  Valkyrie::StorageAdapter.register( Rails.root.join("tmp", "files")),



The initializer registers two Valkyrie::MetadataAdapter instances for storing metadata:

  • :postgres which stores metadata in a PostgreSQL database
  • :memory which stores metadata in an in-memory cache (this cache is not persistent, so it is only appropriate for testing)

Other adapter options include Valkyrie::Persistence::BufferedPersister for buffering in memory before bulk updating another persister, Valkyrie::Persistence::CompositePersister for storing in more than one adapter at once, Valkyrie::Persistence::Solr for storing in Solr, and Valkyrie::Persistence::Fedora for storing in Fedora.

The initializer also registers three Valkyrie::StorageAdapter instances for storing files:

  • :disk which stores files on disk
  • :fedora which stores files in Fedora
  • :memory which stores files in an in-memory cache (again, not persistent, so this is only appropriate for testing)

Sample configuration with custom Valkyrie.config.resource_class_resolver:

require 'valkyrie'
Rails.application.config.to_prepare do
  Valkyrie.config.resource_class_resolver = lambda do |resource_klass_name|
    # Do complicated lookup based on the string

Sample configuration: config/valkyrie.yml:

A sample configuration file that configures your application to use different adapters:

  metadata_adapter: postgres
  storage_adapter: disk

  metadata_adapter: memory
  storage_adapter: memory

  metadata_adapter: postgres
  storage_adapter: fedora

For each environment, you must set two values:

  • metadata_adapter is the store where Valkyrie will put the metadata
  • storage_adapter is the store where Valkyrie will put the files

The values are the short names used in your initializer.

Further details can be found on the Persistence Wiki page.


Define a Custom Work

Define a custom work class:

# frozen_string_literal: true
class MyModel < Valkyrie::Resource
  include Valkyrie::Resource::AccessControls
  attribute :title, Valkyrie::Types::Set    # Sets deduplicate values
  attribute :date, Valkyrie::Types::Array   # Arrays can contain duplicate values

Attributes are unordered by default. Adding ordered: true to an attribute definition will preserve the order of multiple values.

attribute :authors, Valkyrie::Types::Array.meta(ordered: true)

Defining resource attributes is explained in greater detail on the Using Types Wiki page.

Work Types Generator

To create a custom Valkyrie model in your application, you can use the Rails generator. For example, to generate a model named FooBar with an unordered title field and an ordered member_ids field:

rails generate valkyrie:resource FooBar title member_ids:array

You can namespace your model class by including a slash in the model name:

rails generate valkyrie:resource Foo/Bar title member_ids:array

Read and Write Data

# initialize a metadata adapter
adapter = Valkyrie::MetadataAdapter.find(:postgres)

# create an object
object1 = title: 'My Cool Object', authors: ['Jones, Alice', 'Smith, Bob']
object1 = object1)

# load an object from the database
object2 = adapter.query_service.find_by(id:

# load all objects
objects = adapter.query_service.find_all

# load all MyModel objects
Valkyrie.config.metadata_adapter.query_service.find_all_of_model(model: MyModel)

The Wiki documents the usage of Queries, Persistence, and ChangeSets and Dirty Tracking.

Concurrency Support

A Valkyrie repository may have concurrent updates, for example, from a load-balanced Rails application, or from multiple Sidekiq background workers). In order to prevent multiple simultaneous updates applied to the same resource from losing or corrupting data, Valkyrie supports optimistic locking. How to use optimistic locking with Valkyrie is documented on the Optimistic Locking Wiki page.

The Public API

Valkyrie's public API is defined by the shared specs that are used to test each of its core classes. This include change sets, resources, persisters, adapters, and queries. When creating your own kinds of these kinds of classes, you should use these shared specs to test your classes for conformance to Valkyrie's API.

When breaking changes are introduced, necessitating a major version change, the shared specs will reflect this. When new features are added and a minor version is released there will be no change to the existing shared specs, but there may be new ones. These new shared specs will fail in your application if you have custom adapters, but your application will still work.

Using the shared specs in your own models is described in more detail on the Shared Specs Wiki page.

Fedora 5 Compatibility

When configuring your adapter, include the fedora_version parameter in your metadata or storage adapter config. If Fedora requires auth, you can also include that in the URL, e.g.:
  fedora_version: 5

Installing a Development environment

With Docker

The development and test stacks use fully contained virtual volumes and bind all services to different ports, so they can be running at the same time without issue.

External Requirements

Dependency Setup (Mac OSX)

  1. brew install docker
  2. brew install docker-machine
  3. brew install docker-compose

Starting Docker (Mac OSX)

  1. docker-machine create default
  2. docker-machine start default
  3. eval "$(docker-machine env)"

Starting the development mode dependencies

  1. Start Solr, Fedora, and PostgreSQL with rake docker:dev:daemon (or rake docker:dev:up in a separate shell to run them in the foreground)
  2. Run rake db:create db:migrate to initialize the database
  3. Develop!
  4. Run rake docker:dev:down to stop the server stack
    • Development servers maintain data between runs. To clean them out, run rake docker:dev:clean

To run the test suite with all dependencies in one go

  1. rake docker:spec

To run the test suite manually

  1. Start Solr, Fedora, and PostgreSQL with rake docker:test:daemon (or rake docker:test:up in a separate shell to run them in the foreground)
  2. Run rake db:create db:migrate to initialize the database
  3. Run the gem's RSpec test suite with rspec spec or rake
  4. Run rake docker:test:down to stop the server stack
    • The test stack cleans up after itself on exit.

Without Docker

External Requirements

  • PostgreSQL with the uuid-ossp extension.
    • Note: Enabling uuid-ossp requires database superuser privileges.
      • From psql: alter user [username] with superuser;

To run the test suite

  1. Start Solr and Fedora servers for testing with rake server:test
  2. Run rake db:create (First time only)
  3. Run rake db:migrate


This software has been developed by and is brought to you by the Samvera community. Learn more at the Samvera website.

Samvera Logo


Bug reports and pull requests are welcome on GitHub at

You can’t perform that action at this time.