# How to Add a New Storage Driver to CasaOS: A Complete Implementation Guide

> Learn to add a new storage driver to CasaOS by implementing driver logic and registering it. This guide provides a complete implementation for extending CasaOS functionality.

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

---

**To add a new storage driver to CasaOS, create a Go package that implements the `driver.Driver` interface, register it with `op.RegisterDriver` in an `init` function, and import the package in [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go) to activate the backend.**

CasaOS uses a modular plugin system to support diverse storage backends. When you add a new storage driver to CasaOS, you are implementing a Go package that conforms to the internal driver interfaces and hooks into the registry defined in `internal/op`. This extensible architecture allows the system to discover and initialize your driver at runtime through side-effect imports.

## Understanding the CasaOS Driver Architecture

The driver system relies on two core packages: `internal/driver` defines the interface contracts, while `internal/op` maintains the constructor registry. According to the CasaOS source code, every driver must implement the `driver.Driver` interface, which embeds `Meta`, `Reader`, and optional operation interfaces like `Mkdir` or `Move`. The registry in [`internal/op/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/op/driver.go) stores constructor functions in `driverNewMap`, mapping driver names to factory functions that return new instances.

When CasaOS starts, it imports [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go), which performs side-effect imports of all driver packages. Each driver package contains an `init` function that calls `op.RegisterDriver`, inserting the constructor into the global registry. This design decouples driver implementation from the core system, allowing new backends to be added without modifying central orchestration logic.

## Step-by-Step Implementation Guide

### Create the Driver Package

Start by creating a new directory under `drivers/`, such as `drivers/x/`. The package must import the internal driver abstractions to access the interface definitions and registration functions.

```go
import (
    "github.com/IceWhaleTech/CasaOS/internal/driver"
    "github.com/IceWhaleTech/CasaOS/internal/op"
)

```

This setup links your code to the `driver.Config` struct and the `op.RegisterDriver` function used in subsequent steps.

### Define the Storage Struct and Configuration

Create a struct that embeds `model.StorageA` to inherit common storage fields and define an `Addition` struct for driver-specific configuration. The `Addition` struct typically includes fields like API keys, endpoints, or OAuth credentials.

```go
type X struct {
    model.StorageA          // common storage fields
    Addition               // driver-specific configuration
    AccessToken string     // runtime token, if needed
}

type Addition struct {
    driver.RootID
    ClientID     string `json:"client_id" required:"true" omit:"true"`
    ClientSecret string `json:"client_secret" required:"true" omit:"true"`
}

```

Define a package-level `config` variable of type `driver.Config` that describes the driver's capabilities. As implemented in [`drivers/google_drive/meta.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/google_drive/meta.go), this configuration specifies the driver name, proxy requirements, and default root path.

```go
var config = driver.Config{
    Name:        "X",
    OnlyProxy:   true,
    DefaultRoot: "root",
}

```

### Implement the Required Interfaces

You must implement several interfaces defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go):

**Meta Interface**: Implement `Config() driver.Config`, `GetStorage() *model.StorageA`, `SetStorage(model.StorageA)`, `GetAddition() driver.Additional`, `Init(context.Context) error`, and `Drop(context.Context) error`. The `Init` method handles authentication and setup, while `Drop` handles cleanup.

**Reader Interface**: Implement `List(context.Context, model.Obj, model.ListArgs) ([]model.Obj, error)` to return directory contents, and `Link(context.Context, model.Obj, model.LinkArgs) (*model.Link, error)` to generate download URLs.

**Optional Operation Interfaces**: Implement `MakeDir`, `Move`, `Rename`, `Copy`, `Remove`, or `Put` only if your storage backend supports those operations. These are defined as separate interfaces in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go).

### Register the Driver with the Internal Registry

Add an `init` function that calls `op.RegisterDriver`, passing a constructor function that returns a new instance of your driver. The registry links this constructor to the name specified in `config.Name`.

```go
func init() {
    op.RegisterDriver(func() driver.Driver { return &X{} })
}

```

This registration populates the `driverNewMap` in [`internal/op/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/op/driver.go), making your driver available to `op.GetDriverNames()` and `op.GetDriverInfoMap()`.

### Expose the Driver to the Build System

Import your driver package in [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go) using a blank import to ensure the `init` function executes during program startup.

```go
import (
    _ "github.com/IceWhaleTech/CasaOS/drivers/x"
    // existing imports …
)

```

This side-effect import triggers the registration chain without exposing the package's symbols directly.

### Add Driver Assets (Optional)

If your driver requires a UI icon, reference the asset path in your `Addition` struct (e.g., `Icon: "./img/driver/X.svg"`) and store the SVG file under `static/img/driver/`. This allows the CasaOS frontend to display the correct branding for your storage backend.

## Complete Code Example

Below is a minimal implementation skeleton for a hypothetical driver `X` located in [`drivers/x/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/x/drive.go):

```go
package x

import (
    "context"
    "net/http"

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

type X struct {
    model.StorageA
    Addition
    AccessToken string
}

// ---- Meta ---------------------------------------------------------
func (d *X) Config() driver.Config { return config }
func (d *X) GetAddition() driver.Additional { return &d.Addition }
func (d *X) Init(ctx context.Context) error { /* obtain token, etc. */ return nil }
func (d *X) Drop(ctx context.Context) error { return nil }

// ---- Reader -------------------------------------------------------
func (d *X) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
    // fetch file list from the remote service
    return nil, nil
}
func (d *X) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
    // build a download URL
    return &model.Link{
        Method: http.MethodGet,
        URL:    "https://example.com/download/" + file.GetID(),
    }, nil
}

// ---- User ---------------------------------------------------------
func (d *X) GetUserInfo(ctx context.Context) (string, error) { return "user@example.com", nil }
func (d *X) GetInfo(ctx context.Context) (string, string, string, error) { return "", "", "", nil }

// ---- Registration -------------------------------------------------
func init() {
    op.RegisterDriver(func() driver.Driver { return &X{} })
}

```

Accompany this with the configuration file [`drivers/x/meta.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/x/meta.go):

```go
package x

import "github.com/IceWhaleTech/CasaOS/internal/driver"

type Addition struct {
    driver.RootID
    ClientID     string `json:"client_id" required:"true" omit:"true"`
    ClientSecret string `json:"client_secret" required:"true" omit:"true"`
}

var config = driver.Config{
    Name:        "X",
    OnlyProxy:   true,
    DefaultRoot: "root",
}

```

## Key Source Files and Interfaces

Understanding the following files is essential when you add a new storage driver to CasaOS:

- [`internal/op/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/op/driver.go): Contains the registry implementation including `RegisterDriver`, `GetDriverNew`, and `GetDriverInfoMap`.
- [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go): Defines the core interfaces `Driver`, `Meta`, `Reader`, `User`, and optional operation interfaces like `Mkdir` and `Move`.
- [`drivers/google_drive/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/google_drive/drive.go): Reference implementation showing a complete driver with OAuth and API integration.
- [`drivers/google_drive/meta.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/google_drive/meta.go): Demonstrates proper `Addition` struct tagging and `driver.Config` definition.
- [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go): Contains `model.StorageA`, the base struct embedded by all driver implementations.
- [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go): The central import file that triggers driver registration via side-effect imports.

## Testing and Verification

After implementing your driver, run `go test ./...` to ensure your code compiles and passes existing unit tests. Verify that `op.GetDriverNames()` returns your driver name and that `op.GetDriverInfoMap()` contains the configuration fields from your `Addition` struct. Test the driver's lifecycle by initializing it through the CasaOS API, checking that `Init` properly authenticates and that `List` and `Link` return valid data structures.

## Summary

- **Create a package** under `drivers/` that imports `internal/driver` and `internal/op`.
- **Embed `model.StorageA`** and define an `Addition` struct for configuration, using tags like `json:"client_id" required:"true"`.
- **Implement `Meta` and `Reader`** interfaces from [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go), plus optional operation interfaces as needed.
- **Register via `init`** by calling `op.RegisterDriver` with a constructor function.
- **Import in [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go)** using a blank import to trigger registration at startup.
- **Reference existing drivers** like Google Drive in `drivers/google_drive/` as working templates for your implementation.

## Frequently Asked Questions

### What is the minimum interface required to implement a CasaOS storage driver?

At minimum, you must implement the `Meta` interface (`Config`, `GetStorage`, `SetStorage`, `GetAddition`, `Init`, `Drop`) and the `Reader` interface (`List`, `Link`) defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go). These allow CasaOS to initialize the driver, retrieve configuration, and perform basic read operations. Additional interfaces like `Mkdir` or `Move` are only required if your backend supports those operations.

### How does CasaOS discover new drivers at runtime?

CasaOS discovers drivers through the registry in [`internal/op/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/op/driver.go). When you add a blank import of your driver package to [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go), Go executes the package's `init` function during program startup. This function calls `op.RegisterDriver`, which stores a constructor in the `driverNewMap`, making the driver available to the rest of the system via `op.GetDriverNames()`.

### Can I add a storage driver without modifying CasaOS core files?

Yes. You only need to create a new package under `drivers/` and add a single import line to [`drivers/all.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/all.go). You do not need to modify [`internal/op/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/op/driver.go) or any other core orchestration code. The driver system is designed to be extensible through side-effect imports and the registration pattern, keeping your changes isolated to your new driver package and the import list.

### Where should I store driver-specific assets like icons?

Store SVG or image assets in `static/img/driver/` (or the equivalent location in your CasaOS build) and reference them in your `Addition` struct using a relative path like `"./img/driver/X.svg"`. The CasaOS frontend uses this path to display the driver icon in the storage management UI.