Portal Community
  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

Configuration

Connection

FieldRequiredDescription
accessKeyIdRequiredAWS Access Key ID. Store in BizFirst Credentials Manager.
secretKeyRequiredAWS Secret Access Key. Never log or expose.
sessionTokenOptionalSTS session token for temporary credentials.
regionRequiredAWS region of the destination bucket. For cross-region copies, use the destination region here.

Operation Fields

FieldRequiredDescription
sourceBucketRequiredName of the source bucket containing the object to copy.
sourceKeyRequiredFull key path of the source object.
destBucketRequiredName of the destination bucket. May be the same as sourceBucket for same-bucket copy.
destKeyRequiredFull key path for the destination object. Must be different from sourceKey if using the same bucket.
serverSideEncryptionOptionalEncryption for the destination copy. Default: AES256. Options: aws:kms, none.
cannedAclOptionalACL for the destination object. Default: private. Options: public-read.

Sample Configuration

{
  "connection": {
    "accessKeyId": "{{ $credentials.s3_prod.accessKeyId }}",
    "secretKey": "{{ $credentials.s3_prod.secretKey }}",
    "region": "us-east-1"
  },
  "operation": {
    "resource": "object",
    "action": "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 CodeCause & Resolution
NoSuchKeyThe source object does not exist. Verify the sourceBucket and sourceKey using bucket/search before copying.
AccessDeniedThe IAM identity lacks s3:GetObject on the source or s3:PutObject on the destination. Update the IAM policy to include both permissions.
NoSuchBucketThe source or destination bucket does not exist. Create the destination bucket using bucket/create before attempting the copy.
ObjectNotInActiveTierErrorThe 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

FieldTypeDescription
statusstringsuccess on successful copy.
errorCodestringEmpty string on success.
sourceBucketstringThe source bucket.
sourceKeystringThe source object key.
destBucketstringThe destination bucket.
destKeystringThe destination object key.
eTagstringETag of the destination copy.
copiedAtstringISO 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

ExpressionResult
{{ $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 AreaRecommendation
Credential StorageStore credentials in BizFirst Credentials Manager. Never hardcode.
IAM PermissionsGrant 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 UniquenessAlways use expressions that generate unique destination keys — avoid copying over an existing object unless that is intentional.
Encryption ConsistencyApply the same or stricter encryption to the destination copy. Never downgrade from KMS to AES256 when copying regulated data.
Cross-Region CostsCross-region copies incur data transfer fees. Batch cross-region copies during off-peak hours where possible.
Glacier Pre-CheckBefore 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 TrailLog sourceKey, destKey, and copiedAt in the workflow audit trail for every copy operation.
Move PatternS3 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