object/copy FormID 20506
Copy an object within or between S3 buckets without downloading to local storage.
Server-Side Operation:
object/copy is performed entirely within AWS infrastructure. No data is transferred through the workflow executor. This makes it fast, bandwidth-free, and suitable for copying large objects between buckets, including cross-region copies.
When to Use
- Archive processed files: After processing, copy files from a hot
STANDARDlanding bucket to a coldGLACIERarchive bucket without re-uploading. - CDN origin sync: Copy approved assets from an internal review bucket to a CDN origin bucket, making them publicly accessible.
- Template duplication: Copy a master document template to a tenant-specific working location before applying data merge operations.
- Storage class migration: Change the storage class of an existing object by copying it to the same bucket with a different
storageClass. - Cross-region replication trigger: Manually replicate specific objects to a disaster recovery bucket in a secondary region when automated replication is not enabled.
Configuration
Connection
Credentials and region are not fields on this operation. Wire an S3 Server satellite node into this node's input. The satellite holds the vault credential (
ApiKey type — Username = access key ID, Password = secret key), the target AWS region, and an optional Service URL override for S3-compatible backends. Its values are merged onto this node at execution time and take precedence over anything set locally — both source and destination bucket must be reachable from the same connected satellite/credential. See S3 Server (satellite) for the full field reference.
Tenant-prefixed: both
sourceKey and destKey are auto-prepended with tenants/{tenantId}/ before the request is sent to S3. The values you type are what other S3 nodes in this workflow should reuse; the output's effectiveSourceKey/effectiveDestKey fields carry the literal keys actually used, for use with the AWS console, CLI, or other external tools.
Operation Fields
| Field | Required | Description |
|---|---|---|
sourceBucket | Required | Name of the source bucket containing the object to copy. |
sourceKey | Required | Full key path of the source object. |
destBucket | Required | Name of the destination bucket. May be the same as sourceBucket for same-bucket copy. |
destKey | Required | Full key path for the destination object. Must be different from sourceKey if using the same bucket. |
serverSideEncryption | Optional | Encryption for the destination copy. Default: AES256. Options: aws:kms, none. |
cannedAcl | Optional | ACL for the destination object. Default: private. Options: public-read. |
Sample Configuration
// Credentials + region resolved from the connected S3 Server satellite — see s3-server-satellite.html
{
"resource": "object",
"operation": "copy",
"sourceBucket": "acme-processing-queue",
"sourceKey": "incoming/{{ $node.FileRecord.output.fileName }}",
"destBucket": "acme-processed-archive",
"destKey": "archive/{{ $now | date: 'YYYY/MM/DD' }}/{{ $node.FileRecord.output.fileName }}",
"serverSideEncryption": "AES256",
"cannedAcl": "private"
}
Validation Errors
| Error Code | Cause & Resolution |
|---|---|
NoSuchKey | The source object does not exist. Verify the sourceBucket and sourceKey using bucket/search before copying. |
AccessDenied | The IAM identity lacks s3:GetObject on the source or s3:PutObject on the destination. Update the IAM policy to include both permissions. |
NoSuchBucket | The source or destination bucket does not exist. Create the destination bucket using bucket/create before attempting the copy. |
ObjectNotInActiveTierError | The source object is stored in GLACIER or DEEP_ARCHIVE and must be restored before it can be copied. Initiate a restore request first. |
Output
Success Port
| Field | Type | Description |
|---|---|---|
status | string | success on successful copy. |
errorCode | string | Empty string on success. |
sourceBucket | string | The source bucket. |
sourceKey | string | The source object key. |
destBucket | string | The destination bucket. |
destKey | string | The destination object key. |
eTag | string | ETag of the destination copy. |
copiedAt | string | ISO 8601 timestamp of the copy operation. |
Error Port
On failure, activates with errorCode, errorMessage, and httpStatusCode. Handle NoSuchKey to alert on missing source objects and ObjectNotInActiveTierError to trigger a GLACIER restore sub-workflow.
Sample Output
{
"status": "success",
"errorCode": "",
"sourceBucket": "acme-processing-queue",
"sourceKey": "incoming/expense-report-q2-2026.xlsx",
"destBucket": "acme-processed-archive",
"destKey": "archive/2026/05/26/expense-report-q2-2026.xlsx",
"eTag": "\"a3cce0963a6a4b4f3e09d2e1c8f2a1b7\"",
"copiedAt": "2026-05-26T12:00:44Z"
}
Expression Reference
| Expression | Result |
|---|---|
{{ $node.CopyToArchive.output.destKey }} | Destination key — store in database as the new canonical object reference. |
{{ $node.CopyToArchive.output.eTag }} | ETag of the copy — verify integrity against source ETag for audit. |
{{ $node.CopyToArchive.output.copiedAt }} | Copy timestamp — log in workflow execution audit record. |
{{ $node.CopyToArchive.output.destBucket }} | Destination bucket — update database record to reflect new object location. |
Node Policies & GuardRails
| Policy Area | Recommendation |
|---|---|
| Credential Storage | Store credentials in BizFirst Credentials Manager. Never hardcode. |
| IAM Permissions | Grant s3:GetObject on the source bucket and s3:PutObject on the destination bucket. For cross-account copies, configure bucket policies on both sides. |
| Destination Key Uniqueness | Always use expressions that generate unique destination keys — avoid copying over an existing object unless that is intentional. |
| Encryption Consistency | Apply the same or stricter encryption to the destination copy. Never downgrade from KMS to AES256 when copying regulated data. |
| Cross-Region Costs | Cross-region copies incur data transfer fees. Batch cross-region copies during off-peak hours where possible. |
| Glacier Pre-Check | Before copying, verify the source object is not in GLACIER or DEEP_ARCHIVE. Add a pre-flight bucket/search check if storage class is uncertain. |
| Audit Trail | Log sourceKey, destKey, and copiedAt in the workflow audit trail for every copy operation. |
| Move Pattern | S3 has no native move operation. To move an object: copy first, then delete the source with object/delete only after confirming copy success. |
Examples
Example 1: Archive After Processing
After an ETL workflow processes incoming files, copy them to a date-partitioned archive bucket and delete the original from the landing zone.
// Node: CopyToArchive (S3 — object/copy)
{
"sourceBucket": "acme-ingest-landing",
"sourceKey": "incoming/{{ $node.ProcessFile.output.fileName }}",
"destBucket": "acme-long-term-archive",
"destKey": "processed/{{ $now | date: 'YYYY/MM/DD' }}/{{ $node.ProcessFile.output.fileName }}",
"serverSideEncryption": "AES256"
}
// On success: object/delete source file
Example 2: CDN Publish Workflow
After an asset passes review, copy it from the review bucket to the public CDN origin bucket.
// Node: PublishAsset (S3 — object/copy)
{
"sourceBucket": "acme-review-staging",
"sourceKey": "pending/{{ $node.ApprovedAsset.output.assetKey }}",
"destBucket": "acme-cdn-origin",
"destKey": "assets/{{ $node.ApprovedAsset.output.assetKey }}",
"cannedAcl": "public-read"
}
// Next: InvalidateCloudFrontCache for destKey
Example 3: Storage Class Migration
Move objects older than 90 days from STANDARD to STANDARD_IA by copying to the same key with a different storage class.
// Node: MigrateStorageClass (S3 — object/copy, inside Loop)
{
"sourceBucket": "acme-documents",
"sourceKey": "{{ $loop.currentItem.objectKey }}",
"destBucket": "acme-documents",
"destKey": "{{ $loop.currentItem.objectKey }}",
"serverSideEncryption": "AES256",
"storageClass": "STANDARD_IA"
}
// Note: copying to same key/bucket changes the storage class