minio-d ~main

MinIO client library for D, using vibe.d


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

MinIO / S3 Object Storage

A MinIO / S3-compatible object storage client library for the D programming language, built on vibe.d.

Supports bucket management, object CRUD, listing with pagination, presigned URLs, and SigV4 authentication.

Table of Contents

Installation

Add to your dub.sdl:

dependency "minio-d" version="~>1.0.0"

Or dub.json:

"dependencies": {
    "minio-d": "~>1.0.0"
}

Quick Start

import minio;
import std.stdio;

void main()
{
    // Connect to MinIO
    auto client = new MinioClient("localhost:9000", "minioadmin", "minioadmin");

    // Create a bucket
    if (!client.bucketExists("my-bucket"))
        client.createBucket("my-bucket");

    // Upload data
    auto data = cast(const(ubyte)[]) "Hello, MinIO!";
    client.putObject("my-bucket", "greeting.txt", data, "text/plain");

    // Download and print
    auto result = client.getObject("my-bucket", "greeting.txt");
    writeln(cast(string) result.data);
    // Output: Hello, MinIO!

    // Clean up
    client.deleteObject("my-bucket", "greeting.txt");
}

Client Construction

Explicit credentials

auto client = new MinioClient(
    "localhost:9000",   // endpoint
    "minioadmin",       // access key
    "minioadmin",       // secret key
    false,              // useTLS (default: false)
    "us-east-1"         // region (default: "us-east-1")
);

From environment variables

Reads MINIO_ACCESS_KEY / MINIO_SECRET_KEY (or AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY):

auto creds = envCredentials();
auto client = new MinioClient("localhost:9000", creds);

With TLS

auto client = new MinioClient("s3.example.com", "key", "secret", true);

Bucket Operations

listBuckets

auto buckets = client.listBuckets();
foreach (b; buckets)
    writeln(b.name, " created ", b.creationDate);
// Output:
// my-bucket created 2026-03-15T10:30:00.000Z
// backups created 2026-01-01T00:00:00.000Z

createBucket

client.createBucket("new-bucket");

bucketExists

if (client.bucketExists("my-bucket"))
    writeln("Bucket exists");
else
    writeln("Bucket not found");
// Output: Bucket exists

Object Operations

putObject

Upload raw bytes with a content type:

auto data = cast(const(ubyte)[]) "file contents here";
client.putObject("my-bucket", "docs/readme.txt", data, "text/plain");

uploadFile

Upload a file from disk:

client.uploadFile("my-bucket", "images/photo.jpg", "/path/to/photo.jpg", "image/jpeg");

getObject

Download an object into memory:

auto result = client.getObject("my-bucket", "docs/readme.txt");

writeln("Content-Type: ", result.contentType);
writeln("Size: ", result.contentLength, " bytes");
writeln("ETag: ", result.etag);
writeln("Content: ", cast(string) result.data);
// Output:
// Content-Type: text/plain
// Size: 18 bytes
// ETag: "d3b07384d113edec49eaa6238ad5ff00"
// Content: file contents here

Custom metadata is available via result.metadata:

foreach (key, value; result.metadata)
    writeln("x-amz-meta-", key, ": ", value);

getObject (streaming)

Process the response without buffering the entire body:

client.getObject("my-bucket", "large-file.bin", (scope HTTPClientResponse resp) {
    auto reader = resp.bodyReader;
    // process reader stream...
});

downloadFile

Download an object directly to a file on disk:

client.downloadFile("my-bucket", "images/photo.jpg", "/tmp/photo.jpg");

import std.file : getSize;
writeln("Downloaded: ", getSize("/tmp/photo.jpg"), " bytes");
// Output: Downloaded: 245832 bytes

headObject

Get object metadata without downloading the body:

auto head = client.headObject("my-bucket", "docs/readme.txt");

writeln("Content-Type: ", head.contentType);
writeln("Size: ", head.contentLength);
writeln("ETag: ", head.etag);
writeln("Last-Modified: ", head.lastModified);
// Output:
// Content-Type: text/plain
// Size: 18
// ETag: "d3b07384d113edec49eaa6238ad5ff00"
// Last-Modified: Fri, 28 Mar 2026 14:30:00 GMT

deleteObject

client.deleteObject("my-bucket", "docs/readme.txt");

Listing Objects

listObjects

List objects with optional prefix, delimiter, and pagination:

// List all objects in a bucket
auto result = client.listObjects("my-bucket");
foreach (obj; result.objects)
    writeln(obj.key, "  ", obj.size, " bytes");
// Output:
// docs/readme.txt  18 bytes
// images/photo.jpg  245832 bytes
// images/logo.png  12048 bytes

With prefix filter:

// List only objects under images/
auto result = client.listObjects("my-bucket", "images/");
foreach (obj; result.objects)
    writeln(obj.key, "  ", obj.size, " bytes");
// Output:
// images/photo.jpg  245832 bytes
// images/logo.png  12048 bytes

With delimiter for directory-like listing:

// List "directories" at root level
auto result = client.listObjects("my-bucket", null, "/");
foreach (prefix; result.commonPrefixes)
    writeln("DIR  ", prefix);
foreach (obj; result.objects)
    writeln("FILE ", obj.key, "  ", obj.size, " bytes");
// Output:
// DIR  docs/
// DIR  images/

With custom page size:

// Fetch only 10 objects per request
auto page = client.listObjects("my-bucket", null, null, 10);
writeln("Got ", page.objects.length, " objects, more: ", page.isTruncated);
// Output: Got 10 objects, more: true

Manual pagination:

string token = null;
int total = 0;
while (true)
{
    auto page = client.listObjects("my-bucket", null, null, 100, token);
    total += page.objects.length;
    if (!page.isTruncated)
        break;
    token = page.nextContinuationToken;
}
writeln("Total objects: ", total);
// Output: Total objects: 1523

listAllObjects

Automatically fetches all pages:

auto result = client.listAllObjects("my-bucket", "images/");
writeln("Total images: ", result.objects.length);
foreach (obj; result.objects)
    writeln("  ", obj.key, "  ", obj.size, " bytes");
// Output:
// Total images: 3
//   images/logo.png  12048 bytes
//   images/photo.jpg  245832 bytes
//   images/banner.webp  98400 bytes

Presigned URLs

Generate temporary URLs for direct client access without credentials.

presignedGetUrl

import core.time : seconds;

// Default expiry: 1 hour
auto url = client.presignedGetUrl("my-bucket", "images/photo.jpg");
writeln(url);
// Output: http://localhost:9000/my-bucket/images/photo.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...

// Custom expiry: 5 minutes
auto shortUrl = client.presignedGetUrl("my-bucket", "images/photo.jpg", 300.seconds);

presignedPutUrl

auto url = client.presignedPutUrl("my-bucket", "uploads/new-file.bin", 600.seconds);
writeln(url);
// Output: http://localhost:9000/my-bucket/uploads/new-file.bin?X-Amz-Algorithm=AWS4-HMAC-SHA256&...

Types

S3Object

struct S3Object
{
    string key;           // Object key (path)
    string etag;          // MD5 hash of content
    ulong size;           // Size in bytes
    string lastModified;  // ISO 8601 timestamp
    string storageClass;  // e.g. "STANDARD"
}

GetObjectResult

struct GetObjectResult
{
    ubyte[] data;            // Object body
    string contentType;      // MIME type
    ulong contentLength;     // Size in bytes
    string etag;             // MD5 hash
    string[string] metadata; // Custom x-amz-meta-* headers
}

HeadObjectResult

struct HeadObjectResult
{
    string contentType;
    ulong contentLength;
    string etag;
    string lastModified;
    string[string] metadata;
}

ListObjectsResult

struct ListObjectsResult
{
    S3Object[] objects;              // Objects in this page
    string[] commonPrefixes;         // "Directory" prefixes (when using delimiter)
    bool isTruncated;                // More pages available
    string nextContinuationToken;    // Token for next page
}

BucketInfo

struct BucketInfo
{
    string name;
    string creationDate;
}

Error Handling

Operations throw MinioException on failure:

try
{
    auto result = client.getObject("my-bucket", "nonexistent.txt");
}
catch (MinioException e)
{
    writeln("Status: ", e.statusCode);   // 404
    writeln("Code: ", e.errorCode);      // "NoSuchKey"
    writeln("Message: ", e.msg);         // "NoSuchKey (404): The specified key does not exist."
}

Common error codes:

StatusCodeMeaning
404NoSuchKeyObject not found
404NoSuchBucketBucket not found
403AccessDeniedInvalid credentials or permissions
409BucketAlreadyOwnedByYouBucket already exists
400InvalidBucketNameInvalid bucket name

Compatibility

Works with:

  • MinIO (primary target)
  • Amazon S3
  • Any S3-compatible storage (Backblaze B2, Wasabi, DigitalOcean Spaces, etc.)

Requires vibe.d ~>0.10.2.

License

MIT

Authors:
  • Photosynthesis
Dependencies:
vibe-d
Versions:
1.0.0 2026-Apr-04
~main 2026-Apr-04
Show all 2 versions
Download Stats:
  • 0 downloads today

  • 0 downloads this week

  • 4 downloads this month

  • 4 downloads total

Score:
0.1
Short URL:
minio-d.dub.pm