# How to Implement Custom Storage Drivers in CasaOS: A Complete Developer Guide

> Learn to implement custom storage drivers in CasaOS by following our developer guide. Integrate any backend with CasaOS's storage service using its plugin architecture and Go interfaces.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: how-to-guide
- Published: 2026-06-27

---

**CasaOS discovers custom storage drivers through a plugin architecture that requires implementing Go interfaces defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go), enabling any conforming backend to integrate with the storage service.**

CasaOS is an open-source home server system that abstracts cloud storage through a modular driver system. To add support for a new cloud provider or proprietary storage API, developers must build a driver package that satisfies the core interfaces and register it with the internal factory. This guide explains the exact implementation steps, file paths, and method signatures required to create custom storage drivers in CasaOS based on the current source code architecture.

## Understanding the CasaOS Driver Interface Architecture

### Core Interfaces in internal/driver/driver.go

The storage subsystem defines several contracts that every driver must satisfy. According to the source code in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go), these interfaces segregate capabilities:

- **Meta**: Handles configuration and lifecycle. Required methods include `Config() Config`, `GetStorage() *model.StorageA`, `SetStorage(model.StorageA)`, `GetAddition() Additional`, `Init(ctx context.Context) error`, and `Drop(ctx context.Context) error`.
- **Reader**: Provides read-only operations. While it defines no mandatory methods, drivers typically expose listing functions here.
- **User**: Supplies user context and credentials. Requires `GetUserInfo(ctx context.Context) (string, error)` and `GetInfo(ctx context.Context) (string, string, string, error)`.
- **Optional Writer Interfaces**: Implement `Writer`, `Mkdir`, `Move`, `Rename`, `Copy`, `Remove`, or `Put` only if your backend supports modifications.

### The Storage Model

CasaOS uses a generic representation of remote file systems through `model.StorageA`. This struct, defined in [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go), acts as the bridge between the UI and your driver. The `Meta` interface supplies a pointer to this model via `GetStorage` and `SetStorage`, allowing the driver to persist state.

## How CasaOS Discovers and Loads Drivers

The **storage service** ([`service/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/storage.go)) orchestrates driver initialization at startup. It reads the global configuration, invokes the factory function `driver.New(cfg.Name)`, and calls `Init` on each instance:

```go
// Simplified excerpt from service/storage.go
for _, cfg := range cfgs {
    drv, err := driver.New(cfg.Name)   // factory returns concrete driver
    if err == nil {
        _ = drv.Init(ctx)               // initialise the driver
        s.drivers[cfg.Name] = drv
    }
}

```

The factory function in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) uses a switch statement to map configuration names to concrete implementations. This is where you must register your custom driver.

## Step-by-Step Guide to Building a Custom Driver

### Step 1: Create the Driver Package

Create a new directory under `drivers/` for your backend:

```bash
mkdir -p drivers/mycloud

```

### Step 2: Implement the Meta Interface

Your driver struct must embed `driver.Config` and implement lifecycle methods:

```go
type MyCloud struct {
    cfg     driver.Config
    storage *model.StorageA
}

func (d *MyCloud) Config() driver.Config           { return d.cfg }
func (d *MyCloud) GetStorage() *model.StorageA   { return d.storage }
func (d *MyCloud) SetStorage(s model.StorageA)     { d.storage = &s }
func (d *MyCloud) GetAddition() driver.Additional  { return nil }

func (d *MyCloud) Init(ctx context.Context) error {
    // Authentication and setup logic here
    return nil
}

func (d *MyCloud) Drop(ctx context.Context) error {
    // Cleanup logic here
    return nil
}

```

### Step 3: Implement the User Interface

Provide the root folder path and driver metadata:

```go
func (d *MyCloud) GetUserInfo(ctx context.Context) (string, error) {
    return d.cfg.DefaultRoot, nil
}

func (d *MyCloud) GetInfo(ctx context.Context) (string, string, string, error) {
    return "MyCloud", "v1.0", d.cfg.Name, nil
}

```

### Step 4: Implement Read Operations

At minimum, implement a `List` method that the UI can call to enumerate files:

```go
func (d *MyCloud) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
    // Call MyCloud API and translate response to []model.Obj
    return nil, nil
}

```

### Step 5: Add Write Capabilities (Optional)

If your backend supports uploads, implement the `Put` interface:

```go
func (d *MyCloud) Put(ctx context.Context, dst model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
    // Upload implementation with progress reporting
    return nil
}

```

Similarly, implement `Remove`, `Mkdir`, `Move`, `Rename`, or `Copy` only as needed.

### Step 6: Register the Driver in the Factory

Open [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) and add your driver to the `New` function:

```go
func New(name string) (driver.Driver, error) {
    switch name {
    case "mycloud":
        return &mycloud.MyCloud{cfg: driver.Config{Name: name}}, nil
    // existing cases...
    default:
        return nil, fmt.Errorf("unknown driver %s", name)
    }
}

```

### Step 7: Configure and Build

Add a configuration block to `conf/conf.conf.sample`:

```json
"mycloud": {
    "name": "mycloud",
    "default_root": "/",
    "only_proxy": false
}

```

Rebuild the project:

```bash
make build

```

## Complete Skeleton Driver Example

Below is a minimal, compilable driver skeleton for [`drivers/mycloud/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/mycloud/driver.go):

```go
package mycloud

import (
    "context"

    "github.com/IceWhaleTech/CasaOS/internal/driver"
    "github.com/IceWhaleTech/CasaOS/model"
)

type MyCloud struct {
    cfg     driver.Config
    storage *model.StorageA
}

// Meta interface implementation
func (d *MyCloud) Config() driver.Config           { return d.cfg }
func (d *MyCloud) GetStorage() *model.StorageA   { return d.storage }
func (d *MyCloud) SetStorage(s model.StorageA)     { d.storage = &s }
func (d *MyCloud) GetAddition() driver.Additional  { return nil }
func (d *MyCloud) Init(ctx context.Context) error { return nil }
func (d *MyCloud) Drop(ctx context.Context) error { return nil }

// User interface implementation
func (d *MyCloud) GetUserInfo(ctx context.Context) (string, error) {
    return d.cfg.DefaultRoot, nil
}
func (d *MyCloud) GetInfo(ctx context.Context) (string, string, string, error) {
    return "MyCloud", "v0.1", d.cfg.Name, nil
}

// Reader implementation
func (d *MyCloud) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
    // Translate API response to model.Obj slice
    return nil, nil
}

// Optional Writer implementation
func (d *MyCloud) Put(ctx context.Context, dst model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
    return nil
}

```

## Key Source Files for Reference

Study these implementations to understand production patterns:

- [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) – Core interface definitions (`Meta`, `Reader`, `User`)
- [`internal/driver/config.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/config.go) – Configuration struct used by all drivers
- [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go) – Generic storage models (`StorageA`, `Obj`)
- [`drivers/onedrive/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/onedrive/drive.go) – Full-featured reference driver
- [`drivers/dropbox/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/dropbox/drive.go) – Alternative API style example
- [`service/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/storage.go) – Driver initialization and management logic
- `conf/conf.conf.sample` – Configuration schema examples

## Testing Your Custom Storage Driver

1. **Unit Testing**: Create [`drivers/mycloud/driver_test.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/mycloud/driver_test.go) to exercise `Init`, `List`, and any write methods in isolation.
2. **Integration Testing**: Run `go test ./...` from the project root. The storage service will attempt to load your driver if the configuration block is present.
3. **Manual Verification**: Start CasaOS with your configuration enabled, open the web UI, and verify that the new storage appears and correctly lists files.

## Summary

- Create a new package under `drivers/` implementing the **Meta**, **User**, and **Reader** interfaces defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go).
- Register the driver in the `New` factory function within [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) to enable instantiation by name.
- Add configuration entries in `conf/conf.conf.sample` so the storage service can discover and initialize your driver.
- Optional write support requires implementing granular interfaces like **Put**, **Remove**, or **Mkdir** rather than a monolithic requirement.
- Reference existing drivers like [`drivers/onedrive/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/onedrive/drive.go) for production-ready patterns involving OAuth and pagination.

## Frequently Asked Questions

### How do I register a new storage driver in CasaOS?

Register your driver by adding a case to the factory function in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go). The function receives a name string from the configuration and returns a concrete instance of your driver, allowing the storage service in [`service/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/storage.go) to manage it during runtime.

### What is the minimum interface implementation required for a read-only driver?

You must implement the **Meta** interface for configuration and lifecycle management, the **User** interface for providing root folder paths and credentials, and at minimum a `List` method that matches the signature used by existing drivers to return `[]model.Obj`.

### Where does CasaOS store driver configuration?

Driver configuration is defined by the struct in [`internal/driver/config.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/config.go) and populated from the global configuration file (typically `conf/conf.conf.sample`). The storage service passes this configuration to your driver's `Init` method during the initialization loop.

### Can I implement only specific write operations like upload but not delete?

Yes, CasaOS uses capability-based interfaces for write operations. You can implement only the **Put** interface for file uploads without implementing **Remove**, **Mkdir**, or **Move**, making the driver functional for uploads while preventing unsupported operations in the UI.