go
AWS SDK for Go v2
Install
go get github.com/aws/aws-sdk-go-v2/config \
github.com/aws/aws-sdk-go-v2/credentials \
github.com/aws/aws-sdk-go-v2/service/s3 \
github.com/aws/aws-sdk-go-v2/feature/s3/managerConfigure
Configure the endpoint, region, credential and bucket in this tool’s vocabulary. Path-style addressing is recommended for dotted bucket names and clients without nested wildcard TLS, but virtual-hosted addressing is also supported.
| In AWS SDK for Go v2 | Set it to |
|---|---|
| o.BaseEndpoint | https://s3.canada.popcloud.ca |
| config.WithRegion | canada |
| credentials.NewStaticCredentialsProvider | PCAK00EXAMPLEKEYID00 |
| credentials.NewStaticCredentialsProvider | <your secret access key> |
| o.UsePathStyle | true |
export AWS_ACCESS_KEY_ID=PCAK00EXAMPLEKEYID00
export AWS_SECRET_ACCESS_KEY=<your secret access key>
export AWS_ENDPOINT_URL=https://s3.canada.popcloud.ca
export AWS_REGION=canada
export POPCLOUD_BUCKET=pc-your-org-mediaThese are example values. Sign in and every snippet on this site fills in with your own endpoint, key and bucket.
func newClient(ctx context.Context) (*s3.Client, error) {
cfg, err := config.LoadDefaultConfig(ctx,
config.WithRegion(os.Getenv("AWS_REGION")), // canada
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
os.Getenv("AWS_ACCESS_KEY_ID"),
os.Getenv("AWS_SECRET_ACCESS_KEY"),
"", // no session token: PopCloud credentials are long-lived
)),
)
if err != nil {
return nil, err
}
return s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String(os.Getenv("AWS_ENDPOINT_URL")) // https://s3.<region>.popcloud.ca
// Recommended for predictable custom-endpoint behavior. Virtual-hosted
// requests are supported too for ordinary single-label bucket names.
o.UsePathStyle = true
}), nil
}Use it
Upload an object
func upload(ctx context.Context, client *s3.Client, bucket, key string, body []byte) error {
_, err := client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: bytes.NewReader(body),
ContentType: aws.String("text/plain"),
})
return err
}Upload a large object
// The uploader handles multipart, concurrency and retries — use it whenever you
// do not control the size.
func uploadLarge(ctx context.Context, client *s3.Client, bucket, key string, r io.Reader) error {
uploader := manager.NewUploader(client, func(u *manager.Uploader) {
u.PartSize = 8 * 1024 * 1024
u.Concurrency = 4
})
_, err := uploader.Upload(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: r,
})
return err
}Download an object
func download(ctx context.Context, client *s3.Client, bucket, key string) ([]byte, error) {
out, err := client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
return nil, err
}
defer out.Body.Close()
return io.ReadAll(out.Body)
}List a prefix
func listPrefix(ctx context.Context, client *s3.Client, bucket, prefix string) ([]string, error) {
var keys []string
pages := s3.NewListObjectsV2Paginator(client, &s3.ListObjectsV2Input{
Bucket: aws.String(bucket),
Prefix: aws.String(prefix),
})
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
return nil, err
}
for _, obj := range page.Contents {
keys = append(keys, aws.ToString(obj.Key))
}
}
return keys, nil
}Presign a URL
func presign(ctx context.Context, client *s3.Client, bucket, key string) (string, error) {
signer := s3.NewPresignClient(client)
req, err := signer.PresignGetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
}, s3.WithPresignExpires(time.Hour)) // 7 days is the hard maximum
if err != nil {
return "", err
}
// Anyone holding req.URL can read the object until it expires, with no
// credentials at all.
return req.URL, nil
}Delete an object
func remove(ctx context.Context, client *s3.Client, bucket, key string) error {
_, err := client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
return err
}What to watch for
These apply to AWS SDK for Go v2 specifically. The full list covers the platform.
- You’ll see
- 405 MethodNotAllowed from CreateBucket or DeleteBucket — `aws s3 mb`, `mc mb`, or a tool provisioning its own bucket on first run.
- Why
- Bucket lifecycle belongs to the control plane, which also allocates the storage account, the data-plane key and the CORS rules that come with it. Letting the edge create buckets would create half of one.
- Instead
- Create buckets in the dashboard, or with `POST /v1/buckets` on the control-plane API. Everything object-level then works normally against that bucket.
How this page is kept true
Every snippet above was extracted from examples/go/aws-sdk-go-v2, a program that uploads, downloads, compares bytes, lists, presigns and cleans up after itself. It runs in CI against a live sandbox organisation via make docs-verify-go. If it stops passing, this page is wrong and we treat that as a bug in the product.
Not yet run against the live sandbox — the runner is wired, the first verified run stamps this line.