All Products
Search
Document Center

Object Storage Service:Use lifecycle rules based on last access time to implement intelligent data tiering

Last Updated:Mar 20, 2026

Lifecycle rules based on last access time automatically identify cold data by monitoring actual access patterns, then transition objects to lower-cost storage classes — without manual log analysis or scripting.

Use this approach when access patterns across objects in the same path differ. For example, if a path contains both frequently accessed and rarely accessed files that were uploaded at similar times, a last-modification-time rule would treat them identically. A last-access-time rule transitions only the cold files. If all objects in a path age uniformly regardless of access, use last-modification-time rules instead.

Prerequisites

Before you begin, make sure you have:

  • Access tracking enabled on the target bucket

  • Submitted a support ticket if you need to transition objects to Archive, Cold Archive, or Deep Cold Archive storage class (Standard to Infrequent Access (IA) transitions do not require a ticket)

Important

After your ticket is approved, objects transitioned from Standard or IA to Archive, Cold Archive, or Deep Cold Archive using a last-access-time policy will have their last access time set to the time access tracking was enabled for the bucket.

Scenario

A multimedia platform stores two types of data in examplebucket:

PathContentAccess patternPolicy
data/WMV live streams and MP4 moviesWMV files: infrequent after 2 months. MP4 files: accessed repeatedly within 6-month cycles.Transition to IA 200 days after last access; stay in IA if accessed again.
log/Application logsLow activity within 3 months; almost none after 6 months.Transition to IA 120 days after last access, then to Archive 250 days after last access.

With last-access-time rules, frequently accessed MP4 files remain in Standard automatically. MP4 files untouched for 200 days transition to IA. A last-modification-time rule cannot make this distinction — it would transition all files based on upload date alone.

The policies above are examples. Adjust thresholds based on your actual access patterns and cost requirements.

Enable access tracking and create lifecycle rules

Use the OSS console

Step 1: Enable access tracking

  1. Log on to the OSS console.

  2. In the left navigation pane, click Buckets. Find and click the target bucket.

  3. In the left navigation pane, choose Data Management > Lifecycle.

  4. On the Lifecycle page, turn on the Enable Access Tracking switch.

After you enable access tracking, OSS sets the last access time for all existing objects in the bucket to the time access tracking was enabled.

Step 2: Create lifecycle rules

  1. On the Lifecycle page, click Create Rule.

  2. In the Create Lifecycle Rule panel, configure rules for the data/ and log/ prefixes as follows.

Rule for the `data/` prefix

SettingValue
StatusStart
Applied toMatch by Prefix
Prefixdata/
Object lifecycleSpecify Days
Lifecycle-based rulesLast Access Time: 200 days → Infrequent Access (Data remains in IA after being accessed)

Rule for the `log/` prefix

SettingValue
StatusStart
Applied toMatch by Prefix
Prefixlog/
Object lifecycleSpecify Days
Lifecycle-based rulesLast Access Time: 120 days → Infrequent Access (Data remains in IA after being accessed)
Last Access Time: 250 days → Archive
  1. Click OK.

Use an Alibaba Cloud SDK

Only the Java, Python, and Go SDKs support lifecycle rules based on last access time. Enable access tracking for the bucket before creating these rules.

The examples below use two key parameters:

  • IsAccessTime: true — base the transition on last access time, not last modification time

  • ReturnToStdWhenVisit: false — objects stay in the transitioned storage class when accessed again (they do not return to Standard)

Step 1: Enable access tracking

Python

# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# Load credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())

endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
region = "cn-hangzhou"

bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)

# Enable access tracking. To disable it later, first remove all last-access-time lifecycle rules.
bucket.put_bucket_access_monitor("Enabled")

Java

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.AccessMonitor;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Replace with your actual endpoint. Example: China (Hangzhou).
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Load credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
        EnvironmentVariableCredentialsProvider credentialsProvider =
            CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        String bucketName = "examplebucket";
        String region = "cn-hangzhou";

        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
            .endpoint(endpoint)
            .credentialsProvider(credentialsProvider)
            .clientConfiguration(clientBuilderConfiguration)
            .region(region)
            .build();

        try {
            // Enable access tracking. To disable it later, first remove all last-access-time lifecycle rules.
            ossClient.putBucketAccessMonitor(bucketName, AccessMonitor.AccessMonitorStatus.Enabled.toString());
        } catch (OSSException oe) {
            System.out.println("Error Code: " + oe.getErrorCode());
            System.out.println("Request ID: " + oe.getRequestId());
        } catch (ClientException ce) {
            System.out.println("Client error: " + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Go

package main

import (
	"context"
	"flag"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

var (
	region     string
	bucketName string
)

func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
}

func main() {
	flag.Parse()

	if len(bucketName) == 0 {
		log.Fatalf("invalid parameters, bucket name required")
	}
	if len(region) == 0 {
		log.Fatalf("invalid parameters, region required")
	}

	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	client := oss.NewClient(cfg)

	// Enable access tracking. To disable it later, first remove all last-access-time lifecycle rules.
	request := &oss.PutBucketAccessMonitorRequest{
		Bucket: oss.Ptr(bucketName),
		AccessMonitorConfiguration: &oss.AccessMonitorConfiguration{
			Status: oss.AccessMonitorStatusEnabled,
		},
	}

	result, err := client.PutBucketAccessMonitor(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to enable access tracking: %v", err)
	}
	log.Printf("access tracking enabled: %#v\n", result)
}

Step 2: Create lifecycle rules

All three examples configure the same two rules:

  • rule1 (data/): transition to IA after 200 days of no access; stay in IA if accessed again

  • rule2 (log/): transition to IA after 120 days, then to Archive after 250 days

Python

# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
from oss2.models import LifecycleRule, BucketLifecycle, StorageTransition

# Load credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')

# rule1: data/ prefix — transition to IA 200 days after last access; stay in IA when accessed again.
rule1 = LifecycleRule('rule1', 'data/', status=LifecycleRule.ENABLED)
rule1.storage_transitions = [
    StorageTransition(
        days=200,
        storage_class=oss2.BUCKET_STORAGE_CLASS_IA,
        is_access_time=True,           # base on last access time
        return_to_std_when_visit=False  # stay in IA when accessed again
    )
]

# rule2: log/ prefix — transition to IA 120 days after last access, then to Archive after 250 days.
rule2 = LifecycleRule('rule2', 'log/', status=LifecycleRule.ENABLED)
rule2.storage_transitions = [
    StorageTransition(
        days=120,
        storage_class=oss2.BUCKET_STORAGE_CLASS_IA,
        is_access_time=True,
        return_to_std_when_visit=False
    ),
    StorageTransition(
        days=250,
        storage_class=oss2.BUCKET_STORAGE_CLASS_ARCHIVE,
        is_access_time=False           # Archive transition based on last modification time
    )
]

lifecycle = BucketLifecycle([rule1, rule2])
result = bucket.put_bucket_lifecycle(lifecycle)
print('Lifecycle rules set. Status:', result.status)

Java

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;

public class Lifecycle {

    public static void main(String[] args) throws Exception {
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Load credentials from environment variables OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET.
        EnvironmentVariableCredentialsProvider credentialsProvider =
            CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        String bucketName = "examplebucket";

        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            SetBucketLifecycleRequest request = new SetBucketLifecycleRequest(bucketName);

            // rule1: data/ prefix — transition to IA 200 days after last access; stay in IA when accessed again.
            List<LifecycleRule.StorageTransition> transitions1 = new ArrayList<>();
            LifecycleRule.StorageTransition t1 = new LifecycleRule.StorageTransition();
            t1.setStorageClass(StorageClass.IA);
            t1.setExpirationDays(200);
            t1.setIsAccessTime(true);            // base on last access time
            t1.setReturnToStdWhenVisit(false);   // stay in IA when accessed again
            transitions1.add(t1);

            LifecycleRule rule1 = new LifecycleRule("rule1", "data/", LifecycleRule.RuleStatus.Enabled);
            rule1.setStorageTransition(transitions1);
            request.AddLifecycleRule(rule1);

            // rule2: log/ prefix — transition to IA 120 days after last access, then to Archive after 250 days.
            List<LifecycleRule.StorageTransition> transitions2 = new ArrayList<>();

            LifecycleRule.StorageTransition t2 = new LifecycleRule.StorageTransition();
            t2.setStorageClass(StorageClass.IA);
            t2.setExpirationDays(120);
            t2.setIsAccessTime(true);
            t2.setReturnToStdWhenVisit(false);
            transitions2.add(t2);

            LifecycleRule.StorageTransition t3 = new LifecycleRule.StorageTransition();
            t3.setStorageClass(StorageClass.Archive);
            t3.setExpirationDays(250);
            t3.setIsAccessTime(false);           // Archive transition based on last modification time
            transitions2.add(t3);

            LifecycleRule rule2 = new LifecycleRule("rule2", "log/", LifecycleRule.RuleStatus.Enabled);
            rule2.setStorageTransition(transitions2);
            request.AddLifecycleRule(rule2);

            VoidResult result = ossClient.setBucketLifecycle(request);
            System.out.println("Lifecycle rules set. Status: " + result.getResponse().getStatusCode());
        } catch (OSSException oe) {
            System.out.println("Error Code: " + oe.getErrorCode());
            System.out.println("Request ID: " + oe.getRequestId());
        } catch (ClientException ce) {
            System.out.println("Client error: " + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Go

package main

import (
	"context"
	"flag"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

var (
	region     string
	bucketName string
)

func init() {
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
}

func main() {
	flag.Parse()

	if len(bucketName) == 0 {
		log.Fatalf("invalid parameters, bucket name required")
	}
	if len(region) == 0 {
		log.Fatalf("invalid parameters, region required")
	}

	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	client := oss.NewClient(cfg)

	request := &oss.PutBucketLifecycleRequest{
		Bucket: oss.Ptr(bucketName),
		LifecycleConfiguration: &oss.LifecycleConfiguration{
			Rules: []oss.LifecycleRule{
				{
					// rule1: data/ prefix — transition to IA 200 days after last access; stay in IA when accessed again.
					ID:     oss.Ptr("rule1"),
					Status: oss.Ptr("Enabled"),
					Prefix: oss.Ptr("data/"),
					Transitions: []oss.LifecycleRuleTransition{
						{
							Days:                 oss.Ptr(int32(200)),
							StorageClass:         oss.StorageClassIA,
							IsAccessTime:         oss.Ptr(true),  // base on last access time
							ReturnToStdWhenVisit: oss.Ptr(false), // stay in IA when accessed again
						},
					},
				},
				{
					// rule2: log/ prefix — transition to IA 120 days after last access, then to Archive after 250 days.
					ID:     oss.Ptr("rule2"),
					Status: oss.Ptr("Enabled"),
					Prefix: oss.Ptr("log/"),
					Transitions: []oss.LifecycleRuleTransition{
						{
							Days:                 oss.Ptr(int32(120)),
							StorageClass:         oss.StorageClassIA,
							IsAccessTime:         oss.Ptr(true),
							ReturnToStdWhenVisit: oss.Ptr(false),
						},
						{
							Days:                 oss.Ptr(int32(250)),
							StorageClass:         oss.StorageClassArchive,
							IsAccessTime:         oss.Ptr(true),
							ReturnToStdWhenVisit: oss.Ptr(false),
						},
					},
				},
			},
		},
	}

	result, err := client.PutBucketLifecycle(context.TODO(), request)
	if err != nil {
		log.Fatalf("failed to set lifecycle rules: %v", err)
	}
	log.Printf("lifecycle rules set: %#v\n", result)
}

Use ossutil

Enable access tracking on the bucket, then apply lifecycle rules.

ossutil 2.0

Step 1: Enable access tracking

Create a local file config1.xml:

<?xml version="1.0" encoding="UTF-8"?>
<AccessMonitorConfiguration>
    <Status>Enabled</Status>
</AccessMonitorConfiguration>

Apply it to the bucket:

ossutil api put-bucket-access-monitor --bucket bucketname --access-monitor-configuration file://config1.xml

Step 2: Create lifecycle rules

Create a local file config2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LifecycleConfiguration>
  <Rule>
    <ID>rule1</ID>
    <Prefix>data/</Prefix>
    <Status>Enabled</Status>
    <Transition>
      <Days>200</Days>
      <StorageClass>IA</StorageClass>
      <IsAccessTime>true</IsAccessTime>
      <ReturnToStdWhenVisit>false</ReturnToStdWhenVisit>
    </Transition>
  </Rule>
  <Rule>
    <ID>rule2</ID>
    <Prefix>log/</Prefix>
    <Status>Enabled</Status>
    <Transition>
      <Days>120</Days>
      <StorageClass>IA</StorageClass>
      <IsAccessTime>true</IsAccessTime>
      <ReturnToStdWhenVisit>false</ReturnToStdWhenVisit>
    </Transition>
    <Transition>
      <Days>250</Days>
      <StorageClass>Archive</StorageClass>
      <IsAccessTime>true</IsAccessTime>
      <ReturnToStdWhenVisit>false</ReturnToStdWhenVisit>
    </Transition>
  </Rule>
</LifecycleConfiguration>

Apply the rules:

ossutil api put-bucket-lifecycle --bucket bucketname --lifecycle-configuration file://config2.xml

ossutil 1.0

Step 1: Enable access tracking

Create config1.xml with the same content as above, then run:

ossutil access-monitor --method put oss://examplebucket/ config1.xml

Step 2: Create lifecycle rules

Create config2.xml with the same content as above, then run:

ossutil lifecycle --method put oss://examplebucket config2.xml

Use the REST API

For custom integrations, call the REST API directly. You must calculate request signatures manually.

What's next