All Products
Search
Document Center

Object Storage Service:Bucket-level retention policy (BucketWorm)

Last Updated:Mar 31, 2026

A bucket-level retention policy for Object Storage Service (OSS), also known as BucketWorm, provides Write-Once-Read-Many (WORM) immutability. This feature prevents objects from being deleted or modified by any user, including the bucket owner, for a specified period. During the retention period, you can only upload new objects and read existing ones. Objects can be modified or deleted only after the retention period expires.

Use cases

The WORM feature of the OSS retention policy helps meet regulatory requirements from the U.S. Securities and Exchange Commission (SEC) and the Financial Industry Regulatory Authority (FINRA). It is suitable for industries such as finance, insurance, healthcare, and securities, and for scenarios such as log data audits for compliance.

Note

OSS is accredited and audited by Cohasset Associates and meets the stringent requirements for the retention of electronic records. OSS buckets with configured retention policies comply with regulations, such as SEC Rule 17a-4(f), FINRA Rule 4511, and Commodity Futures Trading Commission (CFTC) Rule 1.31. For more information, see the OSS Cohasset Assessment Report.

Prerequisites

Ensure that versioning is either enabled or disabled for the bucket where you want to configure a retention policy. You cannot configure a retention policy if versioning is suspended. For more information about versioning, see Versioning.

Usage notes

  • You cannot enable the OSS-HDFS service and configure a retention policy for the same bucket.

  • During the retention period, you can configure a lifecycle rule to transition objects to a different storage class to reduce storage costs while maintaining compliance.

  • A bucket-level retention policy (BucketWorm) and an object-level retention policy (ObjectWorm) are mutually exclusive. You cannot enable both types of retention policies for the same bucket. If a bucket already has a bucket-level retention policy enabled, you cannot enable an object-level retention policy, and vice versa.

How it works

  • Activation rules

    After you create a time-based retention policy, it enters an InProgress state for 24 hours. During this period, the policy protects bucket resources.

    • Within 24 hours of policy creation

      • If you do not lock the retention policy within 24 hours, the bucket owner and authorized users can delete the policy.

      • If you lock the retention policy within 24 hours, the policy cannot be deleted and its retention period cannot be shortened. You can only extend the retention period. The policy protects objects in the bucket. If you attempt to delete or modify these objects, OSS returns a 409 FileImmutable error.

    • More than 24 hours after policy creation

      If you do not lock the retention policy within 24 hours, the policy automatically expires. You can then delete the policy.

  • Deletion rules

    • A time-based retention policy is a metadata attribute of a bucket. When you delete a bucket, its retention policy is also deleted.

    • Within 24 hours of creating the policy, if it is not locked, the bucket owner and authorized users can delete it.

    • If the bucket contains objects that are still within their retention period, you cannot delete the retention policy or the bucket.

  • Example

    Suppose that on June 1, 2022, you create a retention policy with a 30-day retention period for a bucket and lock the policy immediately after creation. You then upload three objects, file1.txt, file2.txt, and file3.txt, at different times. The following table describes the upload times and expiration times of these objects.

    Object name

    Upload time

    Object expiration time

    file1.txt

    April 01, 2022

    April 30, 2022

    file2.txt

    June 01, 2022

    June 30, 2022

    file3.txt

    September 01, 2022

    September 30, 2022

Methods

Use the OSS console

  1. Create a retention policy.

    1. Log on to the OSS console.

    2. Click Buckets, and then click the name of the target bucket.

    3. In the navigation pane on the left, choose Content Security > Bucket-level Retention Policy.

    4. On the Retention Policy page, click Create Policy.

    5. In the Create Policy dialog box, set the Retention Period.

      Note

      The retention period is measured in days and can range from 1 to 25,550.

    6. Click OK.

      Note

      The policy enters the Pending Lock state. This state is valid for 24 hours. During this time, the resources in the bucket are protected. If you decide not to keep the policy, delete it within 24 hours.

  2. Lock the retention policy.

    1. Click Lock.

    2. In the dialog box that appears, click OK.

      Important

      After a retention policy is locked, it cannot be modified or deleted. During the retention period, data in the bucket also cannot be modified or deleted.

  3. (Optional) Modify the retention period.

    1. Click Edit.

    2. In the dialog box that appears, change the retention period.

      Important

      You can only extend the retention period. You cannot shorten it.

Use Alibaba Cloud SDKs

The following code provides examples of how to configure a retention policy by using common SDKs. For information about how to configure a retention policy by using other SDKs, see Introduction to SDKs.

Java

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

public class Demo {

    public static void main(String[] args) throws Exception {
        // In this example, the endpoint of the China (Hangzhou) region is used. Specify your actual endpoint. 
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // Specify the name of the bucket. Example: examplebucket. 
        String bucketName = "examplebucket";
        // Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. 
        String region = "cn-hangzhou";

        // Create an OSSClient instance. 
        // Call the shutdown method to release resources when the OSSClient is no longer in use.
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();

        try {
            // Create an InitiateBucketWormRequest object. 
            InitiateBucketWormRequest initiateBucketWormRequest = new InitiateBucketWormRequest(bucketName);
            // Set the retention period to 1 day. 
            initiateBucketWormRequest.setRetentionPeriodInDays(1);

            // Create a retention policy. 
            InitiateBucketWormResult initiateBucketWormResult = ossClient.initiateBucketWorm(initiateBucketWormRequest);

            // Display the ID of the retention policy. 
            String wormId = initiateBucketWormResult.getWormId();
            System.out.println(wormId);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

PHP

<?php

// Import the autoloader file to load dependencies.
require_once __DIR__ . '/../vendor/autoload.php';

use AlibabaCloud\Oss\V2 as Oss;

// Define command line argument descriptions.
$optsdesc = [
    "region" => ['help' => 'The region in which the bucket is located', 'required' => True], // Required. The region where the bucket is located.
    "endpoint" => ['help' => 'The domain names that other services can use to access OSS', 'required' => False], // Optional. The domain name that other services can use to access OSS.
    "bucket" => ['help' => 'The name of the bucket', 'required' => True], // Required. The name of the bucket.
];

// Generate a long options list to parse command line arguments.
$longopts = \array_map(function ($key) {
    return "$key:"; // Add a colon after each argument to indicate that a value is required.
}, array_keys($optsdesc));

// Parse the command line arguments.
$options = getopt("", $longopts); 

// Check if any required arguments are missing.
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === True && empty($options[$key])) {
        $help = $value['help'];
        echo "Error: the following arguments are required: --$key, $help"; // Prompt the user that a required argument is missing.
        exit(1); 
    }
}

// Get the command line argument values.
$region = $options["region"]; // The region where the bucket is located.
$bucket = $options["bucket"]; // The name of the bucket.

// Load credential information, such as AccessKey ID and AccessKey secret, from environment variables.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// Use the default configurations of the software development kit (SDK).
$cfg = Oss\Config::loadDefault();

// Set the credential provider.
$cfg->setCredentialsProvider($credentialsProvider);

// Set the region.
$cfg->setRegion($region);

// If an endpoint is provided, set the endpoint.
if (isset($options["endpoint"])) {
    $cfg->setEndpoint($options["endpoint"]);
}

// Create an OSS client instance.
$client = new Oss\Client($cfg);

// Create a request object to initialize the retention policy for the bucket. Set the retention period to 3 days.
$request = new Oss\Models\InitiateBucketWormRequest(
    bucket: $bucket, 
    initiateWormConfiguration: new Oss\Models\InitiateWormConfiguration(
        retentionPeriodInDays: 3 // The retention period in days.
));

// Call the initiateBucketWorm method to initialize the retention policy for the bucket.
$result = $client->initiateBucketWorm($request);

// Print the returned result.
printf(
    'status code:' . $result->statusCode . PHP_EOL . // The HTTP response status code.
    'request id:' . $result->requestId . PHP_EOL . // The unique ID of the request.
    'worm id:' . $result->wormId // The ID of the retention policy.
);

Node.js

const OSS = require('ali-oss');

const client = new OSS({
  // Set region to the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set region to oss-cn-hangzhou.
  region: 'yourregion',
  // Obtain access credentials from environment variables. Before you run this code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,  
  authorizationV4: true,
  // Set bucket to your bucket name.
  bucket: 'yourBucketName',
});
// Create a data retention policy.
async function initiateBucketWorm() {
 // Set bucket to your bucket name.
  const bucket = 'yourbucketname'
  // Specify the retention period in days.
  const days = '<Retention Days>'
    const res = await client.initiateBucketWorm(bucket, days)
  console.log(res.wormId)
}

initiateBucketWorm()

Python

import argparse
import alibabacloud_oss_v2 as oss

# Create a command-line argument parser and describe the script's purpose: This sample shows how to initialize the WORM configuration for an OSS bucket.
parser = argparse.ArgumentParser(description="initiate bucket worm sample")

# Add the --region command-line argument, which specifies the bucket region. This argument is required.
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
# Add the --bucket command-line argument, which specifies the bucket name. This argument is required.
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
# Add the --endpoint command-line argument, which specifies the domain name that other services can use to access OSS. This argument is optional.
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
# Add the --retention_period_in_days command-line argument, which specifies the retention period in days. This argument is required.
parser.add_argument('--retention_period_in_days', help='The number of days for which objects can be retained.', required=True)

def main():
    # Parse the command-line arguments to get the user-provided values.
    args = parser.parse_args()

    # Load the access credentials for OSS from environment variables for identity verification.
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    # Create a configuration object using the SDK's default configurations and set the credentials provider.
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    cfg.region = args.region

    # If a custom endpoint is provided, update the endpoint property in the configuration object.
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    # Initialize the OSS client with the configuration to interact with OSS.
    client = oss.Client(cfg)

    # Send a request to initialize the WORM configuration for the specified bucket.
    result = client.initiate_bucket_worm(oss.InitiateBucketWormRequest(
        bucket=args.bucket,  # Bucket name.
        initiate_worm_configuration=oss.InitiateWormConfiguration(
            retention_period_in_days=int(args.retention_period_in_days),  # Retention period in days, converted to an integer.
        ),
    ))

    # Print the status code, request ID, and WORM ID of the operation to confirm the request status.
    print(f'status code: {result.status_code},'
          f' request id: {result.request_id},'
          f' worm id: {result.worm_id}'
    )

# When this script is run directly, call the main function to start the processing logic.
if __name__ == "__main__":
    main()  # Script entry point, where the program flow starts.

Go

package main

import (
	"log"

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

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

	// Create an OSSClient instance.
	// Set yourEndpoint to the Endpoint of the bucket. For example, for a bucket 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 where the bucket is located. For example, for a bucket in the China (Hangzhou) region, set the region to cn-hangzhou. For other regions, use the actual region.
	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("yourRegion"))
	// Set the signature version.
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		log.Fatalf("Error creating OSS client: %v", err)
	}

	// Specify the name of the bucket for which you want to configure a retention policy.
	bucketName := "<yourBucketName>"

	// Set the retention period for objects to 60 days.
	result, err := client.InitiateBucketWorm(bucketName, 60)
	if err != nil {
		log.Fatalf("Error initiating bucket WORM: %v", err)
	}

	log.Println("WORM policy initiated successfully:", result)
}

C++

#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* Initialize information about the account that is used to access OSS. */
            
    /* Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. */
    std::string Endpoint = "yourEndpoint";
    /* Specify the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the region to cn-hangzhou. */
    std::string Region = "yourRegion";
    /* Specify the name of the bucket. Example: examplebucket. */
    std::string BucketName = "examplebucket";

      /* Initialize resources, such as network resources. */
      InitializeSdk();

      ClientConfiguration conf;
      conf.signatureVersion = SignatureVersionType::V4;
      /* Obtain access credentials from environment variables. Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. */
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);
    client.SetRegion(Region);
  
      /* Create a retention policy and set the retention period to 1 day. */
      auto outcome = client.InitiateBucketWorm(InitiateBucketWormRequest(BucketName, 1));

      if (outcome.isSuccess()) {      
            std::cout << " InitiateBucketWorm success " << std::endl;
            std::cout << "WormId:" << outcome.result().WormId() << std::endl;
      }
      else {
        /* Handle exceptions. */
        std::cout << "InitiateBucketWorm fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
      }

      /* Release resources, such as network resources. */
      ShutdownSdk();
      return 0;
}

Use ossutil

You can use the command-line tool ossutil to create a WORM policy. For installation instructions, see Install ossutil.

The following command creates a WORM policy in the examplebucket bucket and sets the retention period to 365 days.

ossutil api initiate-bucket-worm --bucket examplebucket --initiate-worm-configuration "{\"RetentionPeriodInDays\":\"365\"}"

For more information about this command, see initiate-bucket-worm.

Related APIs

The preceding operations are implemented by calling APIs. If your program requires a high degree of customization, you can send REST API requests directly. This requires you to manually write code to calculate a signature. For more information, see InitiateBucketWorm.

Working with versioning

Some scenarios require you to protect data versions, track asset modifications, or meet compliance archiving requirements. For example, you may need to protect data for backup systems such as Veeam, track changes to circuit design diagrams, or archive financial data. In these cases, you must allow continuous data updates and ensure all historical versions cannot be modified or deleted. To do this, create a retention policy and enable versioning for the bucket. Versioning saves previous versions of an object when it is overwritten or deleted, instead of permanently removing them. A retention policy sets a protection period for all object versions in the bucket. During this period, no version can be deleted or modified.

You can configure versioning and retention policies to work together. They follow these principles:

  • Enablement order: There is no required order for enabling versioning and retention policies. Configure them as needed.

  • State transition constraints:

    • After you enable a retention policy, you cannot change the versioning status from Enabled to Suspended.

    • You can enable a retention policy for a bucket that has versioning suspended. After the policy is enabled, you can change the versioning status to Enabled.

  • Object version protection:

    • A retention policy protects all versions of an object. During the protection period, you cannot delete or modify any version.

    • You can upload an object with the same name to create a new version. The new version is also protected by the retention policy.

    • A retention policy does not apply to delete markers. The removal of delete markers is not restricted by the retention policy.

  • Data replication coordination:

    • The source and destination buckets support independent configurations for versioning and retention policies.

    • Version information is transferred during replication. The destination bucket manages versions based on its own configuration.

    • Delete operations for versions in the source bucket are not synchronized to a destination bucket that has an enabled retention policy.

Frequently asked questions

How are object deletions handled when a retention policy and versioning are both enabled?

When a retention policy and versioning are both enabled, deleting an object works as follows:

  • A delete operation creates a delete marker but does not delete previous versions of the object.

  • Retention policies do not protect delete markers. These markers can be processed normally.

  • All object versions cannot be deleted during the retention period, even if a delete marker exists.

  • Lifecycle rules can clean up expired delete markers but cannot delete object versions that are protected by a retention policy.

Can the versioning state be modified after a retention policy is enabled?

After a retention policy is enabled, the following constraints apply to modifying the versioning state:

  • Enabled → Suspended: If versioning is enabled, you cannot change its state to Suspended after the retention policy is locked.

  • Suspended → Enabled: If versioning is suspended, you can still change its state to Enabled after a retention policy is enabled.

  • Not enabled → Enabled: For a bucket that does not have versioning enabled, you can enable versioning after you configure a retention policy.

Does using a retention policy with versioning increase storage costs?

Yes, it incurs additional storage costs for the following main reasons:

  • During the retention period, all object versions are retained and cannot be deleted by lifecycle rules.

  • The accumulation of versions can significantly increase storage usage, especially for frequently updated objects.

  • Set a reasonable retention period for the policy and use lifecycle rules to manage storage class transitions to optimize costs.

What are the advantages of a retention policy?

A retention policy provides compliance storage. During the retention period, data cannot be deleted or modified. In contrast, data protected by a RAM policy or a bucket policy can be modified or deleted.

When should I set a retention policy?

Enable a retention policy on a bucket when you need to store important data for a long time and prevent it from being modified or deleted. Examples include medical records, technical documents, and contracts.

Can I cancel a retention policy?

Whether you can cancel a retention policy depends on its state.

  • In Progress: The bucket owner and authorized users can delete the policy.

  • Locked: No one can delete the policy.

Can I set a retention policy for a specific object?

The bucket-level retention policy (BucketWorm) described in this topic applies only to buckets. It does not apply to directories or individual objects. If you need to set a separate retention policy for an individual object, use the object-level retention policy (ObjectWorm). Note that BucketWorm and ObjectWorm are mutually exclusive. You cannot enable both on the same bucket.

How is the retention period for an object calculated?

The retention period is calculated based on the object's last modified time and the retention period specified in the policy. For example, if Bucket A has a 10 day retention policy and an object was last modified on February 15, 2022, the object is retained until February 25, 2022.

How do I delete a bucket that has a retention policy enabled?

  • If the bucket contains no objects, you can delete it directly.

  • If the bucket contains objects whose retention periods have expired, first delete all objects, and then delete the bucket.

  • If the bucket contains objects that are still within their retention periods, you cannot delete the bucket.

If my OSS account has an overdue payment, will objects that are still within a retention period be retained?

Note: If your account has an overdue payment, Alibaba Cloud will delete the data according to the service suspension rules for overdue payments, even if the objects in the bucket are protected by a retention policy.

Can an authorized RAM user set a retention policy?

The retention policy API is now available and supports RAM policy. Authorized RAM users can create or delete retention policies using the console, API, or SDK.