River Pro requires a few additional steps to get started beyond those of the main River package. This page covers installing Pro for Go, Ruby, and Rust, running its migrations, initializing a client, and preparing a deployment.
Versions and requirements
Use Postgres or a local SQLite database. The examples below use Postgres; see SQLite setup for the differences. Clients in every River language share the schema and migration history, so apply migrations once per database before starting the new application version.
Pro and core River have independent version numbers, as do the packages for each language. Use compatible core and Pro releases, and keep separately installed migration CLIs at the same Pro version as the application.
Use the Go toolchain required by the selected modules’ go.mod files. The current releases require Go 1.26 or newer. River Pro declares its compatible core River dependency; keep the Pro client and driver modules at the same version. Commit go.mod and go.sum after installing or updating them.
Use Ruby 3.2 or newer. The riverqueue-pro gem declares its compatible core riverqueue dependency, which Bundler resolves along with your driver and database adapter. Commit Gemfile and Gemfile.lock so development, CI, and deployment use the same versions.
Use Rust 1.95 or newer when compiling and Postgres 14 or newer when using Postgres. The current Pro version is 0.1.0-alpha.1, paired with River Rust 0.6.0. Keep all Pro crates and the Pro CLI at the same version.
Initial alpha release
River Pro for Rust is available through River’s authenticated Cargo registry. The initial release is an alpha; pin the versions below explicitly when evaluating it.
Quick start
With a River Pro secret obtained during the subscription process, add River Pro to an existing Go module:
export RIVER_PRO_SECRET=river_secret_...export GOPROXY=https://proxy.golang.org,https://river:$RIVER_PRO_SECRET@riverqueue.com/goproxy,directexport GONOSUMDB=riverqueue.com/riverpro,$GONOSUMDB
# install riverpro modules:go get riverqueue.com/riverprogo get riverqueue.com/riverpro/driver/riverpropgxv5
# the main River package is also required:go get github.com/riverqueue/riverAssuming everything worked, Go will have updated the project’s go.mod and go.sum files with new entries for River Pro. For more information on sustainably managing GOPROXY/GONOSUMDB environment variables in a Go project, or to use the riverpro modules in a CI environment, see Installing private packages.
Add the private riverqueue-pro gem to your Gemfile alongside the core gem, a driver, and the adapter for your database. For ActiveRecord and Postgres:
source "https://rubygems.org"
gem "pg"gem "riverqueue"gem "riverqueue-activerecord"
source "https://riverqueue.com/rubygems" do gem "riverqueue-pro"endThe Pro gem is served by River’s private RubyGems source, not rubygems.org. Authenticate using your River Pro license key as the password and river as the username:
bundle config set --local riverqueue.com 'river:river_secret_...'bundle installKeep .bundle/config out of version control. In CI, set BUNDLE_RIVERQUEUE__COM to river:river_secret_... through your secret store. See private package installation for CI and Docker examples.
You can also use riverqueue-sequel, and both drivers support Postgres and SQLite. For SQLite, use the sqlite3 adapter gem. Pro uses the same drivers as the core Ruby client.
Configure a Cargo registry named river in your user ~/.cargo/config.toml:
[registries.river]index = "sparse+https://riverqueue.com/cargo/"credential-provider = "cargo:token"For local development, run this command and enter your River Pro license key (river_secret_...) when prompted:
cargo login --registry riverUse the license key itself as the token, without a username or URL encoding. Keys are available in the customer dashboard. Keep credentials out of source control and deployment images.
In CI, supply CARGO_REGISTRIES_RIVER_TOKEN through the secret store. You can also configure the registry through environment variables instead of a file:
export CARGO_REGISTRIES_RIVER_INDEX='sparse+https://riverqueue.com/cargo/'export CARGO_REGISTRIES_RIVER_CREDENTIAL_PROVIDER='cargo:token'export CARGO_REGISTRIES_RIVER_TOKEN="$RIVER_PRO_SECRET"Here, RIVER_PRO_SECRET is the license key supplied by your CI secret store. The credential provider must be configured for Cargo to read the token variable. See Cargo registry authentication.
User configuration and these environment settings work for both application builds and cargo install. Installing from a registry with cargo install does not read the current project’s .cargo/config.toml; a project-only configuration is insufficient for that command.
The application depends on the library; installing the CLI is a separate step. Add the compatible version pair to your application’s Cargo.toml:
[dependencies]riverqueue = "=0.6.0"riverqueue-pro = { version = "=0.1.0-alpha.1", registry = "river" }serde = { version = "1", features = ["derive"] }sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "postgres", "tls-rustls"] }tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }Run cargo build and commit the application’s Cargo.lock. Use cargo build --locked in CI. The default Pro features include Postgres, workflows, batching, and encryption support. Enable secretbox explicitly to use that cipher.
Install the CLI
Install the migration command before applying the database schema:
River Pro supplies a separate riverpro executable containing the core migration commands and Pro migration lines. With the private package environment configured above, install the version used by your application:
RIVER_PRO_VERSION=$(go list -m -f '{{.Version}}' riverqueue.com/riverpro)go install riverqueue.com/riverpro/cmd/riverpro@"$RIVER_PRO_VERSION"riverpro versionThe executable is installed in GOBIN, or $(go env GOPATH)/bin by default; include that directory in your PATH. Use riverpro for both migration lines. The core river executable does not include Pro migrations.
The core gem supplies the river command, which loads Pro migrations from riverqueue-pro. No separate CLI package is needed. Run it through Bundler to use the versions in your application’s lockfile:
bundle exec river versionThe output includes the core gem, Pro gem, and Ruby runtime versions. Keep the Pro gem, a River driver, and its database adapter in the deployed bundle so migrations can run.
Install the CLI at the same Pro version as the application:
cargo install riverqueue-pro-cli --registry river \ --version 0.1.0-alpha.1 --lockedriverqueue --versionThe version output includes both versions: riverqueue (River Pro) 0.1.0-alpha.1 (River 0.6.0). Without --root, the executable is normally installed in ~/.cargo/bin; include that directory in your PATH. Both Postgres and SQLite support are enabled by default. The CLI contains migration commands; the public CLI’s throughput benchmark is not included.
If riverqueue-cli already installed the public riverqueue executable, add --force to replace it:
cargo install riverqueue-pro-cli --registry river \ --version 0.1.0-alpha.1 --locked --forceInstalling the public CLI over the Pro executable removes --line pro support. Use --root ./river-cli to keep an isolated installation, and invoke ./river-cli/bin/riverqueue directly. --locked uses the CLI package’s lockfile; it does not select the CLI version from the application’s lockfile. See Cargo install.
Running Pro migrations
Most Pro features require additional migrations. Create the application database, then run the standard River migrations before the pro migration line. New installations only need main and pro; the consolidated Pro line includes sequences and workflows.
Set DATABASE_URL to your database connection string (for example, postgres://app_user@localhost/my_app). Run one migration process at a time across all languages. Already-applied versions are skipped, including versions applied by another River language.
Apply and validate both lines with riverpro:
# first, install the standard River migrations:riverpro migrate-up --database-url "$DATABASE_URL"
# then add the pro migration line:riverpro migrate-up --database-url "$DATABASE_URL" --line proriverpro validate --database-url "$DATABASE_URL"riverpro validate --database-url "$DATABASE_URL" --line proThe Ruby river command loads Pro migrations from riverqueue-pro when you select --line pro. With the gem installed in your bundle, run:
bundle exec river migrate-up --database-url "$DATABASE_URL"bundle exec river migrate-up --database-url "$DATABASE_URL" --line probundle exec river validate --database-url "$DATABASE_URL"bundle exec river validate --database-url "$DATABASE_URL" --line proThe CLI detects an installed ActiveRecord or Sequel driver. It supports Postgres and SQLite. See Pro migrations for the Ruby API and schema options.
Run both lines from the Pro-enabled riverqueue executable:
riverqueue migrate-up --database-url "$DATABASE_URL" --line mainriverqueue migrate-up --database-url "$DATABASE_URL" --line proriverqueue validate --database-url "$DATABASE_URL" --line mainriverqueue validate --database-url "$DATABASE_URL" --line promain is the default. Both Postgres and SQLite support are included in the CLI. The compiled executable runs without Cargo at deployment time.
Successful validation exits with status 0; pending migrations or errors return a nonzero status. Validation checks migration history, not whether every database object is unchanged. Use the CLI version matched to the application even when validation succeeds.
For an alternate Postgres schema, create it first and pass the same --schema jobs to both migration lines and their validation commands. Configure the client to use that schema too. See Pro migrations for previews, rollbacks, SQL exports, and programmatic migration APIs.
Initializing a client
Define job arguments and workers and register workers as for core River. Initialize a Pro client with that worker registry, your database connection, and the queues to work:
A River Pro client is initialized similar to a normal River Client, except with the use of the riverpro.NewClient constructor and the riverpropgxv5 driver instead of riverpgxv5:
import ( ...
"github.com/riverqueue/river" "riverqueue.com/riverpro" "riverqueue.com/riverpro/driver/riverpropgxv5")
riverClient, err := riverpro.NewClient(riverpropgxv5.New(dbPool), &riverpro.Config{ Config: river.Config{ Queues: map[string]river.QueueConfig{ river.QueueDefault: {MaxWorkers: 100}, }, Workers: workers, },})if err != nil { // handle error}
if err := riverClient.Start(ctx); err != nil { // handle error}
// During application shutdown, with a context that allows time to drain:if err := riverClient.Stop(shutdownCtx); err != nil { // handle error}The examples use a pgxpool.Pool named dbPool and registered workers. Core APIs remain available on the Pro client through its embedded river.Client. In workers, use riverpro.ClientFromContext[pgx.Tx](ctx) to retrieve the Pro client.
Require riverqueue-pro and initialize River::Pro::Client with a standard Ruby driver and River::Pro::Config. Put normal client settings inside its core: configuration:
require "riverqueue-activerecord"require "riverqueue-pro"
ActiveRecord::Base.establish_connection(ENV.fetch("DATABASE_URL"))driver = River::Driver::ActiveRecord.new
client = River::Pro::Client.new(driver, config: River::Pro::Config.new( core: River::Config.new( queues: {default: 100}, workers: workers ) ))
client.start
# During application shutdown:client.stopRegister workers as in the Ruby worker guide. For Sequel, pass River::Driver::Sequel.new(DB) using your existing database connection. The feature examples assume riverqueue-pro is required and use driver, workers, and client from this setup.
Initialize ProClient with a database, registered workers, and queues:
use riverqueue::{QueueConfig, database::PostgresDatabase};use riverqueue_pro::ProClient;
let client = ProClient::builder(PostgresDatabase::new(pool)) .queue("default", QueueConfig::new(100)) .workers(workers) .build()?;let mut run = client.start()?;run.wait_ready().await?;
// Keep serving until the application's shutdown signal.tokio::signal::ctrl_c().await?;run.stop().await?;The feature examples use a sqlx::PgPool named pool, registered workers, and this client. Run snippets containing .await inside an async function returning Result; Result<(), Box<dyn std::error::Error>> works for setup examples. Create the pool with sqlx::PgPool::connect(&std::env::var("DATABASE_URL")?).await?. Use SqliteDatabase with the sqlite Cargo feature for SQLite.
Core operations remain available through client.insert, client.jobs, and client.queues. Use client.local_queues() for local queue configuration with Pro settings, and client.river() when an API requires &riverqueue::Client. In workers, ProClient::from_context(&context)? retrieves the Pro client.
SQLite
Pro supports the same features on Postgres and SQLite. Use a local database file and create its parent directory before migrating. Follow the SQLite guide for connection and concurrency settings.
Install riverqueue.com/riverpro/driver/riverprosqlite at the same version as the Pro client. Pass riverprosqlite.New(dbPool) to riverpro.NewClient, using a database/sql pool as in the core SQLite setup. Migrate with a SQLite connection string:
export DATABASE_URL='sqlite://./river.db'riverpro migrate-up --database-url "$DATABASE_URL"riverpro migrate-up --database-url "$DATABASE_URL" --line proriverpro validate --database-url "$DATABASE_URL"riverpro validate --database-url "$DATABASE_URL" --line proUse the sqlite3 adapter gem with either riverqueue-activerecord or riverqueue-sequel. Initialize River::Pro::Client with that ordinary Ruby driver. Use a sqlite3: URL for ActiveRecord or a sqlite: URL for Sequel:
# ActiveRecord:export DATABASE_URL='sqlite3:river.db'bundle exec river migrate-up --database-url "$DATABASE_URL"bundle exec river migrate-up --database-url "$DATABASE_URL" --line probundle exec river validate --database-url "$DATABASE_URL"bundle exec river validate --database-url "$DATABASE_URL" --line proFor a SQLite-only application, disable default features on both River crates and enable sqlite, along with the Pro modules you use:
riverqueue = { version = "=0.6.0", default-features = false, features = ["sqlite"] }riverqueue-pro = { version = "=0.1.0-alpha.1", registry = "river", default-features = false, features = ["sqlite", "workflow", "batch", "encrypt"] }sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "sqlite"] }Use riverqueue::database::SqliteDatabase with a sqlx::SqlitePool when building ProClient. The Pro CLI already includes SQLite by default. mode=rwc creates the database file if it is missing:
export DATABASE_URL='sqlite://river.db?mode=rwc'riverqueue migrate-up --database-url "$DATABASE_URL" --line mainriverqueue migrate-up --database-url "$DATABASE_URL" --line proriverqueue validate --database-url "$DATABASE_URL" --line mainriverqueue validate --database-url "$DATABASE_URL" --line proSQLite migration commands do not support --schema.
Pro feature guides
Use the language selector in each guide for its APIs and examples:
- Batch workers
- Global, local, and partitioned concurrency limits
- Dead letter queue
- Durable periodic jobs
- Encrypted jobs and key rotation
- Ephemeral jobs
- Per-queue job retention
- Sequences
- Workflows, signals, and timers
Pro APIs are available through the riverpro package. Features are configured on the client, queues, or individual jobs as shown in each guide. Time intervals use time.Duration; absolute timestamps use time.Time.
Require riverqueue-pro to load the River::Pro APIs. Features are configured on the client, queues, or individual jobs as shown in each guide. Durations are measured in seconds; absolute timestamps use Ruby Time values.
The default Cargo features include batch, encrypt, postgres, and workflow. Enable secretbox explicitly for the built-in encryption cipher. Other Pro features are always included. When disabling defaults, explicitly enable a database backend and the Pro modules you use.
Time intervals use std::time::Duration; absolute timestamps use jiff::Timestamp, also available through riverqueue::jiff.
Deployment
Build the application and prepare its migration command in CI or a container build stage. Keep private package credentials in the build environment using your secret store; see CI and Docker examples.
Build the application and install the matching CLI in the build stage:
go build -o ./bin/app ./cmd/appRIVER_PRO_VERSION=$(go list -m -f '{{.Version}}' riverqueue.com/riverpro)GOBIN="$PWD/river-cli/bin" go install riverqueue.com/riverpro/cmd/riverpro@"$RIVER_PRO_VERSION"Replace ./cmd/app with your application’s main package. Copy bin/app and river-cli/bin/riverpro into the runtime image. Build for the deployment’s operating system and architecture, including any system libraries and CA certificates the binaries need. The migration executable embeds its SQL and runs without Go or private module credentials.
Install the locked bundle while building the release:
BUNDLE_FROZEN=true bundle installInclude Ruby, the installed bundle, Gemfile, and Gemfile.lock in the runtime image, along with the database adapter’s system libraries and CA certificates. Keep the Pro gem and driver in a deployed dependency group. Run bundle exec river from the application directory; the installed gems contain the migration SQL. No package download or private source credential is needed when running migrations.
Build the application and install the matching CLI in the build stage:
cargo build --release --lockedcargo install riverqueue-pro-cli --registry river \ --version 0.1.0-alpha.1 --locked --root ./river-cliCopy the application executable and river-cli/bin/riverqueue into the runtime image, for example at /usr/local/bin/riverqueue. Build for the deployment’s operating system and architecture, and include the system libraries and CA certificates needed by those executables. The CLI embeds its migrations and runs without Cargo, Rust source files, or registry credentials.
Run the migration and validation commands as a deployment job with the database connection configuration. Make the job stop on the first failed command (for example, with set -eu in a shell script), and start the new workers only after it succeeds.
Upgrading
Update compatible core and Pro dependencies together, commit the dependency files, and prepare the matching migration command before deploying:
Update the client and driver together, then tidy the module:
go get riverqueue.com/riverpro@latest riverqueue.com/riverpro/driver/riverpropgxv5@latestgo mod tidySubstitute the SQLite driver if applicable. Commit go.mod and go.sum, and reinstall the CLI using the version from the application module. A previously installed CLI does not update when go.mod changes.
Update Pro and its compatible core dependency together:
bundle update riverqueue riverqueue-proCommit Gemfile.lock and rebuild the deployed bundle. bundle exec river uses that bundle’s versions, so there is no separate CLI to update.
Choose a compatible River and Pro version pair, update the pinned dependencies in Cargo.toml, and refresh the application’s lockfile:
cargo update -p riverqueue -p riverqueue-procargo build --lockedCommit Cargo.toml and Cargo.lock, and install the matching Pro CLI version in the build stage. A globally installed CLI does not update automatically when Cargo.lock changes.
Apply main, then Pro, validate both lines, then deploy the new clients. Preserve this order even when one line has no pending migrations. Review the update guide and release notes for compatibility changes. Rolling back application code does not by itself require rolling back the schema; see migration rollbacks before reverting database changes.
Managing River Pro license keys
River Pro license keys authenticate with the private package sources and Docker registry. An initial license key is provided via email during the subscription process. You can retrieve your key and manage up to 5 keys for your team in the customer dashboard (dash.riverqueue.com).
For guidance on managing these license keys in your team and environments, see:
Use Bundler’s host credentials for local development and BUNDLE_RIVERQUEUE__COM in CI. See private package installation and dependency updates.
Configure Cargo’s credential provider and supply your River Pro license key as CARGO_REGISTRIES_RIVER_TOKEN during builds. The deployed CLI needs the database connection configuration, and does not need Cargo registry credentials. See private package access.
API documentation
River Pro’s riverpro Go package has generated documentation hosted on this website. Docs are available for each released, along with the latest version always available at a fixed URL.
The feature guides document the Ruby APIs alongside their examples. Ruby classes live under River::Pro; the core client and drivers remain under River. Durations in Ruby configuration are measured in seconds.
Generate local API documentation from the application with the dependency installed:
cargo doc --package riverqueue-pro --openThe Rust Pro client guide and CLI guide describe the client APIs and migration commands.