Apache OpenDAL™: Access data freely, painlessly, and efficiently across 50+ storage services.
pkg:cargo/opendal@0.46.x
npx @tessl/cli install tessl/cargo-opendal@0.46.0OpenDAL (Open Data Access Layer) is a unified, high-performance data access library that provides a single API for interacting with 50+ different storage services. It enables developers to write storage-agnostic code that works seamlessly across cloud object storage, file systems, databases, and other data backends.
cargo add opendaluse opendal::{Operator, BlockingOperator, services, layers, Result};Import specific services and layers as needed:
use opendal::services::S3;
use opendal::layers::LoggingLayer;use opendal::{services, Operator, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Initialize a service (S3 example)
let mut builder = services::S3::default();
builder.bucket("my-bucket");
// Create operator with optional layers
let op = Operator::new(builder)?
.layer(opendal::layers::LoggingLayer::default())
.finish();
// Perform operations
op.write("hello.txt", "Hello, World!").await?;
let content = op.read("hello.txt").await?;
let metadata = op.stat("hello.txt").await?;
println!("Content: {}", String::from_utf8_lossy(&content));
println!("Size: {}", metadata.content_length());
Ok(())
}OpenDAL is built around several key architectural components:
Operator/BlockingOperator) across all storage backendsPrimary file and directory operations supporting all major storage patterns. Includes basic CRUD operations, metadata access, and directory management.
impl Operator {
pub async fn read(&self, path: &str) -> Result<opendal::Buffer>;
pub async fn write(&self, path: &str, bs: impl Into<opendal::Buffer>) -> Result<()>;
pub async fn stat(&self, path: &str) -> Result<opendal::Metadata>;
pub async fn delete(&self, path: &str) -> Result<()>;
pub async fn list(&self, path: &str) -> Result<Vec<opendal::Entry>>;
}50+ storage backend implementations providing unified access to cloud storage, file systems, and databases. Each service offers the same API interface while handling service-specific protocols internally.
// Cloud Object Storage
pub struct S3;
pub struct Gcs;
pub struct Azblob;
// File Systems
pub struct Fs;
pub struct Hdfs;
// Databases
pub struct Redis;
pub struct Postgresql;Composable middleware system for adding cross-cutting functionality like logging, retry logic, metrics collection, and performance optimization without changing core business logic.
impl<A> OperatorBuilder<A> {
pub fn layer<L: Layer<A>>(self, layer: L) -> OperatorBuilder<L::LayeredAccessor>;
}
pub struct LoggingLayer;
pub struct RetryLayer;
pub struct MetricsLayer;Comprehensive type system providing storage-agnostic data structures, error handling, and metadata management. Supports both owned and borrowed data with zero-copy optimizations.
pub struct Buffer;
pub struct Entry;
pub struct Metadata;
pub enum Scheme;
pub enum ErrorKind;OpenDAL uses Rust's Result<T, Error> pattern for comprehensive error handling:
use opendal::{Result, Error, ErrorKind};
match op.read("file.txt").await {
Ok(data) => println!("Success: {} bytes", data.len()),
Err(e) if e.kind() == ErrorKind::NotFound => {
println!("File not found");
},
Err(e) => eprintln!("Error: {}", e),
}All storage services follow a consistent builder pattern for configuration:
use opendal::services::S3;
let mut builder = S3::default();
builder
.bucket("my-bucket")
.region("us-west-2")
.access_key_id("key")
.secret_access_key("secret");
let op = Operator::new(builder)?.finish();