Amazon S3 offers different storage classes to help reduce storage costs. One of them is S3 Glacier, designed for storing data that you rarely need to access.
But there's an important detail that can cause confusion when working with archived objects:
Restoring an S3 Glacier object does not automatically move it back to S3 Standard.
Let's understand why this happens, the different Glacier storage classes, and how to bring an archived object back to regular storage.
1. What is Amazon S3 Glacier?
Amazon S3 Glacier is a set of storage classes designed for long-term data archiving.
Instead of paying higher storage costs for files that are rarely accessed, you can move them into Glacier storage classes.
For example:
- Old user-uploaded images.
- Historical reports and documents.
- Database backups.
- Application logs.
- Compliance and audit records.
The trade-off is that some Glacier classes have slower retrieval times and additional retrieval costs.
2. Understanding the three Glacier storage classes
Not every Glacier storage class works the same way.
| Storage class | Retrieval time | Best suited for |
|---|---|---|
Glacier Instant Retrieval (GLACIER_IR) |
Milliseconds | Rarely accessed files that still need immediate access |
Glacier Flexible Retrieval (GLACIER) |
Minutes to hours | Backups and disaster recovery |
Glacier Deep Archive (DEEP_ARCHIVE) |
Hours | Long-term archives and compliance data |
A few important differences:
Glacier Instant Retrieval
- Objects are immediately accessible through normal S3 GET requests.
- No restore request is required.
- Designed for data accessed occasionally but requiring immediate availability.
- Minimum storage duration: 90 days.
Glacier Flexible Retrieval
- Objects are archived and cannot be accessed directly.
- You must initiate a restore request before accessing them.
- Supports Expedited, Standard, and Bulk retrieval.
- Minimum storage duration: 90 days.
Glacier Deep Archive
- Designed for data that is rarely accessed.
- Requires a restore request before accessing objects.
- Supports Standard and Bulk retrieval.
- Minimum storage duration: 180 days.
The important distinction is that Instant Retrieval provides immediate access, whereas Flexible Retrieval and Deep Archive require restoration.
3. What actually happens when you restore an object?
This is where the confusion starts.
Imagine an application stores an image in S3. Over time, a lifecycle policy moves that image into Glacier Flexible Retrieval to reduce storage costs.
Later, the application needs that image again.
You initiate a restore request.
AWS processes the request and creates a temporary accessible copy of the archived object. You specify how many days that temporary copy should remain available.
Once restoration completes, you can access the object.
However, the original object's storage class remains GLACIER.
For example, a HEAD request can return:
{
"StorageClass": "GLACIER",
"Restore": "ongoing-request=\"false\", expiry-date=\"...\""
}
Let's understand these fields:
-
StorageClass: GLACIERmeans the object is still in Glacier Flexible Retrieval. -
ongoing-request="false"means restoration has completed. -
expiry-dateindicates when the temporary restored copy expires.
Restoration makes the object accessible. It does not migrate the object to another storage class.
This distinction is critical when an application expects the object to remain available beyond the restore period.
4. How do you permanently move a restored object back to S3 Standard?
If you need the object to remain available without depending on the temporary restore window, you need another operation.
The solution is to:
- Restore the archived object.
- Wait until restoration completes.
- Copy the restored object to the same bucket and key.
- Specify
STANDARDas the destination storage class.
This creates a new object using S3 Standard storage.
Step 1: Check whether restoration is complete
Using AWS CLI:
BUCKET=only-for-testing
KEY="letsflo-core/dev/_1793103890540/HH0922_166_11.jpg"
aws s3api head-object \
--bucket "$BUCKET" \
--key "$KEY" \
--query '[StorageClass,Restore]'
Make sure the restore status is:
ongoing-request="false"
Do not attempt the copy before restoration completes.
Step 2: Copy the object onto itself
Once restoration is complete:
aws s3 cp \
"s3://$BUCKET/$KEY" \
"s3://$BUCKET/$KEY" \
--storage-class STANDARD \
--force-glacier-transfer
Why copy the object to itself?
Because the copy operation creates a new object at the destination, even when the source and destination use the same bucket and key.
By specifying:
--storage-class STANDARD
we tell S3 to store the resulting object in Standard storage instead of Glacier.
Step 3: Verify the storage class
Run the HEAD request again:
aws s3api head-object \
--bucket "$BUCKET" \
--key "$KEY" \
--query '[StorageClass,Restore]'
Expected result:
[
"STANDARD",
null
]
S3 Standard is the default storage class, so AWS may omit the StorageClass field.
The temporary restore information should no longer be needed for the new Standard object.
5. Performing the same operation using Node.js
In our case, we also needed to perform this operation through the backend's existing AWS configuration.
Using AWS SDK for JavaScript v3, we can use CopyObjectCommand.
const cfg = require("../backend/src/flo/config/dev.js").aws;
const S = require("@aws-sdk/client-s3");
const client = new S.S3Client({
region: cfg.region || "eu-west-1",
credentials: {
accessKeyId: cfg.accessKeyId,
secretAccessKey: cfg.secretAccessKey
},
followRegionRedirects: true
});
const Bucket = cfg.Bucket;
const Key = "letsflo-core/dev/_1793103890540/HH0922_166_11.jpg";
const head = async (label) => {
const result = await client.send(
new S.HeadObjectCommand({ Bucket, Key })
);
console.log(label, {
storageClass: result.StorageClass || "STANDARD",
restore: result.Restore || "no restore"
});
return result;
};
(async () => {
const before = await head("BEFORE");
if (
!before.Restore ||
!before.Restore.includes('ongoing-request="false"')
) {
throw new Error("Object restoration is not complete.");
}
await client.send(
new S.CopyObjectCommand({
Bucket,
Key,
CopySource: encodeURIComponent(`${Bucket}/${Key}`),
StorageClass: "STANDARD",
MetadataDirective: "COPY"
})
);
const after = await head("AFTER");
if (
after.StorageClass &&
after.StorageClass !== "STANDARD"
) {
throw new Error("Storage class verification failed.");
}
console.log("Object successfully moved to STANDARD.");
})().catch(error => {
console.error("ERROR:", error.name, error.message);
process.exitCode = 1;
});
The implementation performs three important operations:
- Checks the existing object's restoration status.
- Copies the restored object using the Standard storage class.
- Verifies the resulting object's storage class.
For production implementations, also consider multipart copy for objects larger than 5 GB, bucket versioning, object tags, encryption, and permissions.
6. Important things to check before doing this in production
Before changing storage classes, consider a few operational details.
Bucket versioning
If versioning is enabled, copying an object to the same key creates a new version. The previous Glacier version can still exist and incur storage charges.
Lifecycle policies
Check whether lifecycle rules automatically move objects back into Glacier. Otherwise, the newly created Standard object might be archived again.
Storage and retrieval costs
Glacier has minimum storage-duration requirements. Moving or deleting objects before those periods expire can result in early deletion charges.
Restoration also incurs retrieval costs, and the temporary restored copy incurs Standard storage charges during its availability period.
Metadata and encryption
Check whether the copy preserves the metadata, tags, encryption settings, and other properties your application depends on. MetadataDirective: "COPY" preserves user-defined metadata, but production implementations should explicitly verify the required properties.
Conclusion
Amazon S3 Glacier is useful for reducing storage costs, but understanding its restoration behavior is equally important.
Remember these three things:
- Glacier Instant Retrieval: Access objects immediately without restoring them.
- Glacier Flexible Retrieval and Deep Archive: Restore objects before accessing them.
-
Need permanent Standard storage? Restore first, then copy the object with
STANDARDas its storage class.
A successful restore request doesn't necessarily mean your storage migration is complete.
Always verify the actual storage class rather than relying only on the restoration status.
Top comments (1)
That HEAD response still saying GLACIER after a restore is a good catch.