Getting started with Morph Volumes
Morph Volumes are persistent S3-compatible storage for build caches, release artifacts, checkpoints, and shared datasets. They use your existing Morph API key, so you can use the web console, the morphcloud volumes CLI, the Python MorphCloudClient().volumes helpers, or any standard S3 client against the same gateway.
The public S3 gateway is live today. You can create buckets from the web console or the S3 API directly, and public_read only matters if you need anonymous object fetches.
Useful links:
- Volumes web guide
- Volumes product page
- Usage dashboard
- CLI reference
- Service usage API: Get User Service Usage
- Service quota API: Get User Service Quota
The user-facing surface is the S3 gateway, the first-party morphcloud volumes CLI, and the Python MorphCloudClient().volumes helper layer. All three support bucket creation, listing, upload, download, and delete flows.
Connection settings
- Base URL:
https://volumes.svc.cloud.morph.so - Stage base URL:
https://volumes.svc.stage.morph.so - Auth: use the same
MORPH_API_KEYas both the S3 access key and secret - Addressing style: path-style
- Region setting: not used by the gateway; if a client insists on a SigV4 region token, any placeholder value such as
us-any-1works - Bucket names: lower-case letters, digits, dots, and hyphens; names are globally unique across active volumes
- Anonymous reads:
GETandHEADonly, and only for volumes already markedpublic_read
Prerequisites
- A Morph API key from the Morph Cloud dashboard
- A bucket name you can create or reuse, for example
team-build-cache - Either the Morph Cloud CLI, the Python SDK, or an S3-compatible client such as AWS CLI v2,
curlwith--aws-sigv4, orboto3
export MORPH_API_KEY="<your-api-key>"
export VOLUME_NAME="team-build-cache"
export MORPH_VOLUMES_BASE_URL=${MORPH_VOLUMES_BASE_URL:-"https://volumes.svc.cloud.morph.so"}
export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-"us-any-1"}
Quickstart
- Morph Cloud CLI
- Python SDK
- AWS CLI
- curl
- Python (boto3)
# The CLI is included with `pip install morphcloud`
# Create a bucket if you don't already have one
morphcloud volumes mb "$VOLUME_NAME"
# List visible buckets for the current org
morphcloud volumes ls
# Upload an artifact
morphcloud volumes cp ./artifact.tar.gz "s3://$VOLUME_NAME/releases/artifact.tar.gz"
# Browse the uploaded prefix
morphcloud volumes ls "s3://$VOLUME_NAME/releases/"
morphcloud volumes tree "s3://$VOLUME_NAME/"
# Download or inspect an object
morphcloud volumes cat "s3://$VOLUME_NAME/releases/artifact.tar.gz"
morphcloud volumes cp "s3://$VOLUME_NAME/releases/artifact.tar.gz" ./downloads/
If you need a non-default endpoint, the CLI can be pointed at stage or another gateway with:
morphcloud --volumes-base-url https://volumes.svc.stage.morph.so volumes ls
import os
from morphcloud import MorphCloudClient
client = MorphCloudClient(
api_key=os.environ["MORPH_API_KEY"],
)
volume_name = os.environ.get("VOLUME_NAME", "team-build-cache")
client.volumes.create_bucket(volume_name)
client.volumes.put_object(
volume_name,
"releases/artifact.txt",
b"hello from morph volumes\n",
content_type="text/plain",
)
print([bucket.name for bucket in client.volumes.list_buckets()])
payload = client.volumes.get_object(volume_name, "releases/artifact.txt")
print(payload.decode("utf-8").strip())
# Optional cleanup once you're done testing.
client.volumes.delete_object(volume_name, "releases/artifact.txt")
client.volumes.delete_bucket(volume_name)
If you need a non-default endpoint, pass volumes_base_url="https://volumes.svc.stage.morph.so" when constructing MorphCloudClient(...), or export MORPH_VOLUMES_BASE_URL before creating the client.
export AWS_ACCESS_KEY_ID="$MORPH_API_KEY"
export AWS_SECRET_ACCESS_KEY="$MORPH_API_KEY"
# Create a bucket
aws --endpoint-url "$MORPH_VOLUMES_BASE_URL" s3 mb "s3://$VOLUME_NAME"
# List visible volumes for the current org
aws --endpoint-url "$MORPH_VOLUMES_BASE_URL" s3 ls
# Upload an artifact
aws --endpoint-url "$MORPH_VOLUMES_BASE_URL" \
s3 cp ./artifact.tar.gz "s3://$VOLUME_NAME/releases/artifact.tar.gz"
# Inspect the uploaded prefix
aws --endpoint-url "$MORPH_VOLUMES_BASE_URL" \
s3 ls "s3://$VOLUME_NAME/releases/"
# Create a bucket
curl --aws-sigv4 "aws:amz:$AWS_DEFAULT_REGION:s3" \
--user "$MORPH_API_KEY:$MORPH_API_KEY" \
--header "x-amz-content-sha256: UNSIGNED-PAYLOAD" \
-X PUT \
"$MORPH_VOLUMES_BASE_URL/$VOLUME_NAME"
# List available volumes
curl --aws-sigv4 "aws:amz:$AWS_DEFAULT_REGION:s3" \
--user "$MORPH_API_KEY:$MORPH_API_KEY" \
--header "x-amz-content-sha256: UNSIGNED-PAYLOAD" \
"$MORPH_VOLUMES_BASE_URL/"
# Upload a file
curl --aws-sigv4 "aws:amz:$AWS_DEFAULT_REGION:s3" \
--user "$MORPH_API_KEY:$MORPH_API_KEY" \
--header "x-amz-content-sha256: UNSIGNED-PAYLOAD" \
--upload-file ./artifact.tar.gz \
"$MORPH_VOLUMES_BASE_URL/$VOLUME_NAME/releases/artifact.tar.gz"
import os
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
endpoint_url=os.getenv("MORPH_VOLUMES_BASE_URL", "https://volumes.svc.cloud.morph.so"),
aws_access_key_id=os.environ["MORPH_API_KEY"],
aws_secret_access_key=os.environ["MORPH_API_KEY"],
region_name=os.getenv("AWS_DEFAULT_REGION", "us-any-1"),
config=Config(s3={"addressing_style": "path"}),
)
volume_name = os.environ.get("VOLUME_NAME", "team-build-cache")
s3.create_bucket(Bucket=volume_name)
print([bucket["Name"] for bucket in s3.list_buckets()["Buckets"]])
s3.upload_file("artifact.tar.gz", volume_name, "releases/artifact.tar.gz")
Use the web dashboard
Prefer a guided workflow?
- Sign in at https://cloud.morph.so
- Open the Volumes console guide at https://cloud.morph.so/web/volumes
- Copy the endpoint, path-style, and auth settings for your client
- Open API Keys in the console if you need a fresh Morph API key
- Open Usage to inspect volume billing snapshots for your active organization
The Volumes page in the web app focuses on connection details, bucket browsing, and billing visibility.
Billing and usage
Morph Volumes are billed from stored GiB-hours rather than compute MCUs.
- Current runtime price:
$0.0054794/GiB-hour - Approximate monthly equivalent:
~$4.00/GiB-month - Usage visibility: see the web Usage page or query Get User Service Usage
- Quotas: query Get User Service Quota
The usage API buckets storage over time by service and resource type. For volumes, the current resource type is volume_billing_snapshot.
Public cache reads
If a volume has been provisioned with public_read, anonymous clients can GET or HEAD individual objects directly:
curl -I "https://volumes.svc.cloud.morph.so/$VOLUME_NAME/releases/artifact.tar.gz"
This is useful for distribution-friendly build caches and published artifacts. Anonymous writes are never allowed.