All Products
Search
Document Center

Object Storage Service:List objects (Go SDK V1)

Last Updated:Mar 20, 2026

Use the OSS Go SDK to list objects in a bucket — by prefix, by page, or by simulated directory structure.

Prerequisites

Before you begin, ensure that you have:

Choose an API

OSS provides two methods for listing objects: ListObjectsV2 and ListObjects. Both return up to 1,000 objects per call, with 100 returned by default.

ListObjectsV2ListObjects
Pagination tokenContinuationToken / NextContinuationTokenMarker / NextMarker
Start positionStartAfterMarker
Owner informationNot included by default; set FetchOwner(true) to includeAlways included
Versioning-enabled bucketsRequiredNot supported

Use ListObjectsV2 for new implementations. ListObjects is provided for compatibility with existing code.

OSS SDK for Go 2.2.5 and later supports returning RestoreInfo in listing results.

How pagination works

Both methods use IsTruncated to indicate whether more objects remain. When IsTruncated is true, pass the token from the response into the next call to retrieve the next page:

  • ListObjectsV2: pass lsRes.NextContinuationToken as ContinuationToken

  • ListObjects: pass lsRes.NextMarker as Marker

All examples below follow this pagination pattern. The loop structure is the same across scenarios — only the filter parameters change.

Usage notes

  • This topic uses the public endpoint for the China (Hangzhou) region. To access OSS from other Alibaba Cloud services in the same region, use an internal endpoint. See Regions and endpoints.

  • To create an OSSClient instance using a custom domain name or Security Token Service (STS), see Configure OSSClient instances.

List all objects

All examples create an OSSClient instance using AuthV4 and credentials from environment variables. The client setup is identical across scenarios.

ListObjectsV2

Using ListObjectsV2:

package main

import (
	"log"
	"time"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	// Obtain access credentials from environment variables. Before you run this sample code, ensure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		log.Fatalf("Failed to create credentials provider: %v", err)
	}

	// Create an OSSClient instance.
	// Set yourEndpoint to the endpoint of the bucket. For example, if the bucket is in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. For other regions, use the actual endpoint.
	// Set yourRegion to the region of the bucket. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou. For other regions, use the actual region.
	client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider), oss.Region("yourRegion"), oss.AuthVersion(oss.AuthV4))
	if err != nil {
		log.Fatalf("Failed to create OSS client: %v", err)
	}

	// Specify the bucket name.
	bucketName := "yourBucketName" // Replace with the actual bucket name.
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		log.Fatalf("Failed to get bucket: %v", err)
	}

	// The initial continuation token.
	continueToken := ""

	for {
		// List all objects.
		lsRes, err := bucket.ListObjectsV2(oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		// Print the results. By default, 100 records are returned at a time.
		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		// If more objects need to be listed, update the continuation token and continue the loop.
		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

	log.Println("All objects have been listed.")
}

ListObjects

Using ListObjects:

package main

import (
	"log"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	// Obtain access credentials from environment variables. Before you run this sample code, ensure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		log.Fatalf("Failed to create credentials provider: %v", err)
	}

	// Create an OSSClient instance.
	// Set yourEndpoint to the endpoint of the bucket. For example, if the bucket is in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. For other regions, use the actual endpoint.
	// Set yourRegion to the region of the bucket. For example, if the bucket is in the China (Hangzhou) region, set the region to cn-hangzhou. For other regions, use the actual region.
	client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider), oss.Region("yourRegion"), oss.AuthVersion(oss.AuthV4))
	if err != nil {
		log.Fatalf("Failed to create OSS client: %v", err)
	}

	// Specify the bucket name.
	bucketName := "yourBucketName" // Replace with the actual bucket name.
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		log.Fatalf("Failed to get bucket: %v", err)
	}

	// List all objects.
	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		// Print the results. By default, 100 records are returned at a time.
		for _, object := range lsRes.Objects {
			log.Printf("Object Name: %s\n", object.Key)
		}

		// If more objects need to be listed, update the marker and continue the loop.
		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

	log.Println("All objects have been listed.")
}

Common scenarios

The following examples build on the basic listing pattern. Each shows only the parameters that differ from the basic case — the client setup and pagination loop remain the same.

List a specific number of objects

Set MaxKeys to limit how many objects each call returns. The maximum is 1,000.

ListObjectsV2

Using ListObjectsV2 — limit to 200 per page:

	maxKeys := 200
	continueToken := ""

	for {
		lsRes, err := bucket.ListObjectsV2(oss.MaxKeys(maxKeys), oss.StartAfter(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s, Owner ID: %s, Owner DisplayName: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass, object.Owner.ID, object.Owner.DisplayName)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.ContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects — limit to 200 per page:

	maxKeys := 200
	lsRes, err := bucket.ListObjects(oss.MaxKeys(maxKeys))
	if err != nil {
		log.Fatalf("Failed to list objects: %v", err)
	}

	log.Printf("Found %d objects:\n", len(lsRes.Objects))
	for _, object := range lsRes.Objects {
		log.Printf("Object: %s\n", object.Key)
	}

	if lsRes.IsTruncated {
		log.Printf("More objects available. NextMarker: %s\n", lsRes.NextMarker)
	} else {
		log.Println("All objects have been listed.")
	}

List objects with a specific prefix

Set the Prefix parameter to filter objects by name prefix. The default page size of 100 applies unless you also set MaxKeys.

ListObjectsV2

Using ListObjectsV2:

	prefix := "my-object-"
	lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix))
	if err != nil {
		log.Fatalf("Failed to list objects: %v", err)
	}

	log.Printf("Found %d objects with prefix '%s':\n", len(lsRes.Objects), prefix)
	for _, object := range lsRes.Objects {
		log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s, Owner ID: %s, Owner DisplayName: %s\n",
			object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass, object.Owner.ID, object.Owner.DisplayName)
	}

	if lsRes.IsTruncated {
		log.Printf("More objects available. Next Continuation Token: %s\n", lsRes.NextContinuationToken)
	} else {
		log.Println("All objects have been listed.")
	}

ListObjects

Using ListObjects:

	prefix := "my-object-"
	lsRes, err := bucket.ListObjects(oss.Prefix(prefix))
	if err != nil {
		log.Fatalf("Failed to list objects: %v", err)
	}

	log.Printf("Found %d objects with prefix '%s':\n", len(lsRes.Objects), prefix)
	for _, object := range lsRes.Objects {
		log.Printf("Object Key: %s\n", object.Key)
	}

	if lsRes.IsTruncated {
		log.Printf("More objects available. Next Marker: %s\n", lsRes.NextMarker)
	} else {
		log.Println("All objects have been listed.")
	}

List objects after a specified starting point

Set StartAfter (ListObjectsV2) or Marker (ListObjects) to resume listing from a specific key. All objects in lexicographical order after that value are returned.

ListObjectsV2

Using ListObjectsV2:

	startAfter := "my-object-"
	lsRes, err := bucket.ListObjectsV2(oss.StartAfter(startAfter))
	if err != nil {
		log.Fatalf("Failed to list objects: %v", err)
	}

	log.Printf("Found %d objects starting after '%s':\n", len(lsRes.Objects), startAfter)
	for _, object := range lsRes.Objects {
		log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s, Owner ID: %s, Owner DisplayName: %s\n",
			object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass, object.Owner.ID, object.Owner.DisplayName)
	}

	if lsRes.IsTruncated {
		log.Printf("More objects available. Next Continuation Token: %s\n", lsRes.NextContinuationToken)
	} else {
		log.Println("All objects have been listed.")
	}

ListObjects

Using ListObjects:

	marker := ""

	for {
		lsRes, err := bucket.ListObjects(oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		log.Printf("Found %d objects:\n", len(lsRes.Objects))
		for _, object := range lsRes.Objects {
			log.Printf("Object: %s\n", object.Key)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

List all objects by page

Set MaxKeys to control page size, and use the continuation token or marker to iterate through all pages.

ListObjectsV2

Using ListObjectsV2 — 100 objects per page:

	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.MaxKeys(100), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		log.Printf("Found %d objects:\n", len(lsRes.Objects))
		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects — 100 objects per page:

	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.MaxKeys(100), oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		log.Printf("Found %d objects:\n", len(lsRes.Objects))
		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

List objects with a specific prefix by page

Combine Prefix and MaxKeys to page through a filtered result set.

ListObjectsV2

Using ListObjectsV2 — prefix my-object-, 80 objects per page:

	prefix := "my-object-"
	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.MaxKeys(80), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		log.Printf("Found %d objects with prefix '%s':\n", len(lsRes.Objects), prefix)
		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects — prefix my-object-, 80 objects per page:

	prefix := "my-object-"
	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.MaxKeys(80), oss.Marker(marker), oss.Prefix(prefix))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		log.Printf("Found %d objects with prefix '%s':\n", len(lsRes.Objects), prefix)
		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

List object metadata in a directory

Set Prefix to a directory path to retrieve all objects in that directory, including their size, last modified time, and storage class.

ListObjectsV2

Using ListObjectsV2:

	continueToken := ""
	prefix := "fun"
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	marker := ""
	prefix := "test"
	for {
		lor, err := bucket.ListObjects(oss.Marker(marker), oss.Prefix(prefix))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lor.Objects {
			log.Printf("Object Key: %s, Type: %s, Size: %d, ETag: %s, LastModified: %s, StorageClass: %s\n",
				object.Key, object.Type, object.Size, object.ETag, object.LastModified.Format(time.RFC3339), object.StorageClass)
		}

		if lor.IsTruncated {
			marker = lor.NextMarker
		} else {
			break
		}
	}

List all subdirectories in a directory

Set Delimiter to / to get subdirectory names without listing objects inside them. Subdirectories appear in CommonPrefixes, not in Objects.

ListObjectsV2

Using ListObjectsV2:

	continueToken := ""
	prefix := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.ContinuationToken(continueToken), oss.Delimiter("/"))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, dirName := range lsRes.CommonPrefixes {
			log.Println("Directory Name:", dirName)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	marker := ""
	prefix := "yourDirPrefix" // Replace with the actual prefix.
	for {
		lor, err := bucket.ListObjects(oss.Marker(marker), oss.Prefix(prefix), oss.Delimiter("/"))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, dirName := range lor.CommonPrefixes {
			log.Println("Directory Name:", dirName)
		}

		if lor.IsTruncated {
			marker = lor.NextMarker
		} else {
			break
		}
	}

List owner information

ListObjectsV2 omits owner information by default. Pass FetchOwner(true) to include it.

	lsRes, err := bucket.ListObjectsV2(oss.FetchOwner(true))
	if err != nil {
		log.Fatalf("Failed to list objects with owner information: %v", err)
	}

	for _, object := range lsRes.Objects {
		log.Printf("Object Key: %s, Owner ID: %s, Display Name: %s\n",
			object.Key, object.Owner.ID, object.Owner.DisplayName)
	}

ListObjects always returns owner information.

Folders

OSS stores objects in a flat structure. A folder is a zero-byte object whose name ends with /. When displayed in the OSS console, such objects appear as folders.

Use Prefix and Delimiter to simulate directory-style listing:

  • `Prefix` only: lists all objects whose names start with the prefix, including those in subdirectories.

  • `Prefix` + `Delimiter(/)`: lists objects and immediate subdirectories in the specified directory. Each subdirectory appears as a single entry in CommonPrefixes; objects inside subdirectories are not listed.

The following examples use a bucket with these objects: oss.jpg, fun/test.jpg, fun/movie/001.avi, and fun/movie/007.avi.

List all objects in a bucket

Both ListObjectsV2 and ListObjects return all four objects when no prefix or delimiter is set:

Objects:
fun/movie/001.avi
fun/movie/007.avi
fun/test.jpg
oss.jpg
CommonPrefixes: (empty)

ListObjectsV2

Using ListObjectsV2:

	startAfter := ""
	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.StartAfter(startAfter), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		if lsRes.IsTruncated {
			startAfter = lsRes.StartAfter
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

List all objects in a specific directory

Set Prefix to the directory path to list all objects in that directory and its subdirectories:

Objects:
fun/movie/001.avi
fun/movie/007.avi
fun/test.jpg
CommonPrefixes: (empty)

ListObjectsV2

Using ListObjectsV2:

	prefix := "aaa/db-init"
	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	prefix := "aaa/db-init" // Replace with the actual prefix.
	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.Prefix(prefix), oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

List objects and subdirectories in a directory

Add Delimiter("/") to separate objects from subdirectories. Immediate subdirectories appear in CommonPrefixes; their contents are not listed.

For prefix = "fun/", the result is:

Objects:
fun/test.jpg

CommonPrefixes:
fun/movie/

ListObjectsV2

Using ListObjectsV2:

	prefix := "" // Set a prefix as needed.
	delimiter := "/"
	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.Delimiter(delimiter), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		for _, commonPrefix := range lsRes.CommonPrefixes {
			log.Printf("Common Prefix: %s\n", commonPrefix)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	prefix := "aaa/db-init/" // Replace with the actual prefix.
	marker := ""
	delimiter := "/"
	for {
		lsRes, err := bucket.ListObjects(oss.Prefix(prefix), oss.Marker(marker), oss.Delimiter(delimiter))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s\n", object.Key)
		}

		for _, commonPrefix := range lsRes.CommonPrefixes {
			log.Printf("Common Prefix: %s\n", commonPrefix)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

Get the size of objects in a directory

Set Prefix to the directory path and read object.Size from each result.

ListObjectsV2

Using ListObjectsV2:

	prefix := "/fun" // Replace with the actual prefix.
	continueToken := ""
	for {
		lsRes, err := bucket.ListObjectsV2(oss.Prefix(prefix), oss.ContinuationToken(continueToken))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Size: %d Byte(s)\n", object.Key, object.Size)
		}

		if lsRes.IsTruncated {
			continueToken = lsRes.NextContinuationToken
		} else {
			break
		}
	}

ListObjects

Using ListObjects:

	prefix := "test/" // Replace with the actual prefix.
	marker := ""
	for {
		lsRes, err := bucket.ListObjects(oss.Prefix(prefix), oss.Marker(marker))
		if err != nil {
			log.Fatalf("Failed to list objects: %v", err)
		}

		for _, object := range lsRes.Objects {
			log.Printf("Object Key: %s, Size: %d Byte(s)\n", object.Key, object.Size)
		}

		if lsRes.IsTruncated {
			marker = lsRes.NextMarker
		} else {
			break
		}
	}

FAQ

Can I sort objects by last modified time when listing them?

No. OSS returns objects in lexicographical order only. To query objects by last modified time, use data indexing.

References