Skip to content

Storage providers

A Provider is one configured object-storage backend inside a Workspace. Clients discover Provider IDs through provider/list; endpoints, regions, addressing mode, and credentials remain server-side configuration.

type selects the server implementation. Omitting it selects generic.

Type Connection Behavior
generic Explicit S3 endpoint Standard S3 operations.
aws Endpoint derived from the Region Standard S3 with AWS bucket-location rules.
minio Explicit MinIO S3 endpoint Currently the same standard operations as generic.
azure Native Blob service endpoint Containers and blobs through the Azure API, using a SAS token.

The server does not infer the type from a Provider ID, display name, or hostname. Unknown types are configuration errors. The previous s3-compatible spelling remains accepted as an alias for generic; config show writes generic.

Selecting a type does not guarantee that every operation is supported or permitted. generic does not disable standard tagging or search operations. minio does not currently enable a separate search implementation.

Google Cloud Storage and Hetzner use generic. Azure Blob Storage uses azure; an Azure-backed S3 gateway can still use generic.

Set icon_path on any Provider to replace its built-in icon:

workspace:
providers:
- id: amazon-s3
display_name: Amazon S3
type: aws
icon_path: /etc/s3lens/images/company.svg
region: eu-west-1
credentials:
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}

The path names a file on the server. Relative paths resolve from the server’s working directory, including when configuration files are merged. Set the path directly in the configuration. Environment references are not expanded for icon_path. Remote URLs are not supported.

PNG, JPEG, GIF, WebP, and SVG files are supported. Each file must be nonempty and at most 256 KiB; all provider images together must fit within 1 MiB. A missing, unreadable, oversized, or unsupported file prevents server startup and identifies the affected Provider. The server reads images at startup, so restart it after changing an image.

The server returns the image as iconDataUrl in provider/list, only for Providers the caller can see. Filesystem paths stay on the server. The web and desktop apps use the custom image in the provider table, switcher, and provider page. Omitting icon_path preserves the built-in icon selected by type.

Use type: aws when the AWS SDK should derive the service endpoint from the Region:

workspace:
id: production
display_name: Production
providers:
- id: amazon-s3
display_name: Amazon S3
type: aws
region: ${AWS_REGION:-eu-west-1}
credentials:
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}
session_token: ${AWS_SESSION_TOKEN:-}

An AWS Provider does not accept a custom endpoint. Use generic for an S3 service with an explicit endpoint.

workspace:
id: self-hosted
display_name: Self-hosted storage
providers:
- id: storage
display_name: Storage
type: generic
endpoint: https://s3.example.com
region: us-east-1
force_path_style: true
credentials:
access_key_id: ${S3_ACCESS_KEY_ID}
secret_access_key: ${S3_SECRET_ACCESS_KEY}

The endpoint must be an HTTP or HTTPS base URL without embedded credentials, query parameters, or a fragment. force_path_style: true is common for self-hosted services whose DNS does not provide virtual-hosted Bucket names.

For MinIO, use type: minio with the same connection fields. Both types require an endpoint and a signing Region. Omitting type does not infer AWS or its endpoint.

Google’s XML API interoperability accepts S3 signatures with Cloud Storage HMAC credentials. Use examples/google/provider.yaml with GCS_ACCESS_KEY_ID and GCS_SECRET_ACCESS_KEY, then run pnpm run dev -- --with google.

The endpoint is https://storage.googleapis.com, the signing region is auto, and path-style addressing supports dotted bucket names. These are HMAC keys, not service-account JSON keys or OAuth tokens. A service-account HMAC key uses its parent project by default. For user HMAC keys, set the default project under Cloud Storage Settings > Interoperability. S3 Lens does not send an explicit project header.

The generic adapter uses the XML API operations. S3 object tags and S3 bucket-policy documents have no documented XML API equivalent. Google IAM policies, labels, and resource tags are separate concepts. Tag-dependent searches can fail on this provider. region signs requests; it does not place a new bucket. Set optional bucket_location to select a Cloud Storage location when creating buckets, or omit it to use Google’s default.

Use examples/hetzner/provider.yaml with HETZNER_ACCESS_KEY_ID, HETZNER_SECRET_ACCESS_KEY, and HETZNER_LOCATION, then run pnpm run dev -- --with hetzner.

The fixture defaults to fsn1 and uses https://fsn1.your-objectstorage.com. Configure one provider per location and project. The location selects both the endpoint and bucket_location, which the generic adapter sends as CreateBucketConfiguration.LocationConstraint. Existing generic configurations that omit bucket_location still send no location constraint. AWS rejects this field because its bucket location follows its region.

Hetzner documents S3 compatibility limits, including unsupported bucket tagging and cross-bucket copies that can fail even within one location. Such provider errors remain errors; S3 Lens does not silently replace a failed copy with a different operation. See Hetzner’s connection guide.

workspace:
providers:
- id: azure
display_name: Azure Blob Storage
type: azure
endpoint: https://${AZURE_STORAGE_ACCOUNT}.blob.core.windows.net
credentials:
sas_token: ${AZURE_STORAGE_SAS_TOKEN}

examples/azure/provider.yaml contains this fragment. Export its variables and run pnpm run dev -- --with azure. Supply the Blob service endpoint without a SAS query. The token belongs in credentials.sas_token, with or without its leading ?; diagnostic configuration output redacts it. Azure rejects S3 configuration fields such as region, force_path_style, and access keys.

This integration currently accepts SAS authentication. It does not acquire Entra tokens or accept storage account keys or connection strings. An account SAS with Blob service access and the needed service, container, and object resource types supports account-wide browsing. Container and object SAS tokens cannot list the account’s containers. Grant only the operations required: listing, reading, creating or writing, deleting, and tags use their corresponding SAS permissions. Exact version deletion requires the version-delete permission. Expired or insufficient tokens return provider errors.

Azure containers appear as buckets, and blobs appear as objects. The adapter supports container discovery, lookup and creation, paginated object listing with folder delimiters, reads and previews, uploads, object deletion, tags, versions, and copy or move operations. Azure version IDs remain opaque. Version pagination resumes after a named version within the original provider page; a removed resume version produces an invalid-cursor error. Azure soft-deleted blobs and snapshots are not represented as S3 delete markers.

Streamed uploads stage 4 MiB blocks and commit only after the received byte count matches the declared length. The adapter supports at most 50,000 blocks, about 195 GiB per streamed upload. Interrupted uploads can leave uncommitted blocks for Azure to expire. Same-provider copies use synchronous Put Blob From URL, with a 5,000 MiB source limit and a condition that prevents overwriting an existing destination. Copies preserve blob tags and require SAS tag permission. A failed copy leaves the source in place.

The following operations return unsupportedOperation:

  • Bucket deletion. Azure deletes a container and all its blobs, with no atomic empty-container condition matching S3 bucket deletion. Delete containers through Azure’s own tools.
  • S3 bucket policies and policy-derived public-access status. Azure IAM and container access policies use different models.
  • S3 multipart-upload discovery, part inspection, and abort. Azure’s uncommitted blocks do not provide the same upload-session contract.

For local verification, pnpm run dev -- --none --with azurite starts the pinned Azurite emulator with public development credentials. Azurite does not cover every cloud operation, including blob versions and Put Blob From URL. Successful local checks do not establish compatibility with every Azure account setting.

The repository includes ready-to-run fixtures that pnpm run dev starts by name:

Fixture S3 endpoint Start command
Garage http://127.0.0.1:3900 pnpm run dev (default)
SeaweedFS http://127.0.0.1:8333 pnpm run dev -- --with seaweedfs
RustFS http://127.0.0.1:9000 pnpm run dev -- --with rustfs
VersityGW http://127.0.0.1:7070 pnpm run dev -- --with versitygw
MinIO (legacy) http://127.0.0.1:9000 pnpm run dev -- --with minio
Azurite http://127.0.0.1:10000/s3lens pnpm run dev -- --with azurite
Google Cloud Storage https://storage.googleapis.com pnpm run dev -- --with google
Hetzner Location-specific S3 endpoint pnpm run dev -- --with hetzner
Azure Blob Storage Account-specific Blob endpoint pnpm run dev -- --with azure
Amazon S3 AWS pnpm run dev -- --with aws
Cloudflare R2 https://<account>.r2.cloudflarestorage.com pnpm run dev -- --with r2

Amazon S3 and Cloudflare R2 have no container; they read real credentials from the environment (S3LENS_DEVELOPMENT_AWS_*, and R2_ACCOUNT_ID plus R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY). MinIO and RustFS share port 9000, so the runner refuses to start them together. The MinIO community project is archived; its fixture is retained as a compatibility target, not as a production recommendation.

Each storage fixture under examples/ contains a provider.yaml fragment; local services also have a Compose file that is merged after examples/base.yaml. Validate and run one without the runner:

Terminal window
docker compose -f examples/compose.yaml up -d seaweedfs
cargo run -- config validate --config examples/base.yaml --config examples/seaweedfs/provider.yaml
cargo run -- serve --config examples/base.yaml --config examples/seaweedfs/provider.yaml

Provider credentials authorize the S3 Lens server against the storage backend. They are separate from S3 Lens authentication and policies. Scope access keys to only the operations and Buckets the deployment needs.

Depending on enabled features, S3 Lens uses listing, get, put, copy, delete, tagging, versioning, multipart-upload, and native Bucket-policy operations. A Provider can accept the connection while rejecting individual operations that it does not implement or that the access key cannot perform; those failures are returned as stable protocol errors without leaking Provider diagnostics.