Skip to main content

Connecting to your storage

Switching backends is a configuration change, not a code change. This page covers the ways to build an operator and the things that trip people up: feature flags and credentials. For the configuration keys of a specific service, see Services.

Enable the service feature

Every service is behind a services-* Cargo feature. Enable the ones you use:

[dependencies]
opendal = { version = "0.57", features = ["services-s3", "services-gcs"] }

The in-memory service is always available; every other service needs its services-* feature. Forgetting the feature is the most common reason a service "doesn't exist" at compile time.

Build an operator

Each service has a builder with checked, discoverable options:

use opendal::services;
use opendal::Operator;

let op = Operator::new(
services::S3::default()
.bucket("my-bucket")
.region("us-east-1")
.endpoint("https://s3.amazonaws.com"),
)?;

A local filesystem operator roots every path under one directory:

let op = Operator::new(services::Fs::default().root("/tmp/opendal"))?;

From a key-value map

When configuration comes from a file or environment, build from key-value pairs instead of naming each setter. The keys are the same as the builder fields:

use std::collections::HashMap;
use opendal::services;
use opendal::Operator;

let cfg = HashMap::from([
("bucket".to_string(), "my-bucket".to_string()),
("region".to_string(), "us-east-1".to_string()),
]);

let op = Operator::from_iter::<services::S3>(cfg)?;

From a URI

Registered services can be constructed from a URI, with the scheme selecting the backend at runtime:

use opendal::Operator;

let op = Operator::from_uri("memory://")?;

Use Operator::via_iter(scheme, pairs) for the same runtime-selected construction with explicit key-value config.

Credentials

Credentials are just more configuration keys. Set them on the builder (for example S3's access_key_id / secret_access_key), or supply them through the key-value map above. Some services can also load credentials from their platform's default sources — see each service's page under Services for the exact keys and credential behavior.

Avoid hard-coding secrets in source. Read them from the environment or a secret manager and pass them in when you build the operator.

One operator per service and root

An operator maps to one service and one root path. To work with two buckets or two roots, build two operators — they are cheap, lightweight handles that are safe to share across threads and tasks.