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.