n8n Amazon S3: Storage Bucket File Workflow Automation
I use Amazon S3 with n8n because object storage is the backbone of modern data pipelines. Whether I’m storing uploaded files, hosting static assets, or archiving backups, S3 handles petabytes of data reliably. n8n connects to S3 through its dedicated node, giving me file uploads, downloads, bucket management, presigned URLs, and event-driven triggers.
S3 organizes data into buckets and objects. Each object has a key (path), metadata, and content. I’ve built workflows that process incoming files, transform them, distribute to multiple buckets, and clean up old data — all without touching the AWS console.
File Upload and Download Operations
The n8n S3 node handles basic file operations with binary data support:
`javascript
// S3 node: upload file to bucket
Operation: Put Object
Bucket: my-n8n-uploads
Key: invoices/2024/INV-001.pdf
Content: {{invoice_pdf_binary}}
ContentType: application/pdf
ACL: private
`
Uploads support multipart transfers for large files. The S3 node automatically splits files above 5MB into parts and reassembles them on the server side. This prevents timeouts and handles unstable connections gracefully.
For downloads, I retrieve objects and pass binary content to downstream nodes:
`javascript
// S3 node: download file
Operation: Get Object
Bucket: my-n8n-uploads
Key: invoices/2024/INV-001.pdf
// Result: binary data available in $binary.data
`
The downloaded binary data flows directly into other nodes. I commonly route it through a Code node for format conversion, then upload the result to a different bucket:
`javascript
// Code node: convert image format
const sharp = require(‘sharp’);
const inputBuffer = Buffer.from(item.json.$binary.data.data, ‘base64’);
const converted = await sharp(inputBuffer)
.resize(800, 600, { fit: ‘contain’ })
.jpeg({ quality: 80 })
.toBuffer();
return [{
json: item.json,
binary: {
data: {
data: converted.toString(‘base64’),
mimeType: ‘image/jpeg’,
fileName: item.json.$binary.data.fileName.replace(‘.png’, ‘.jpg’)
}
}
}];
`
Bucket Management and Lifecycle Policies
I manage buckets through the S3 node’s bucket operations. Creating, listing, and deleting buckets fits naturally into provisioning workflows:
`javascript
// S3 node: create bucket
Operation: Create Bucket
Bucket: my-new-bucket
Region: us-east-1
Storage Class: STANDARD
// S3 node: list objects
Operation: List Objects
Bucket: my-n8n-uploads
Prefix: reports/2024/
Max Keys: 100
`
Lifecycle policies automate data retention. Instead of manually deleting old files, I attach lifecycle rules to buckets:
`javascript
// HTTP Request node: put bucket lifecycle
Method: PUT
URL: https://my-n8n-uploads.s3.amazonaws.com/?lifecycle
Headers: { Content-Type: application/xml }
Body: |
`
The first rule deletes files in the temp/ prefix after 7 days. The second transitions archived files to Glacier storage after 90 days, reducing costs by up to 80%.
Presigned URLs for Secure Access
Presigned URLs grant temporary access to private S3 objects without exposing credentials. I generate them for customer downloads, file sharing, and CDN origin authentication:
`javascript
// S3 node: generate presigned URL
Operation: Presigned URL
Bucket: my-n8n-uploads
Key: reports/client-report-q3.pdf
Expires: 3600
HTTP Method: GET
`
The node returns a URL valid for the specified duration (default 1 hour). I embed this URL in emails sent through the Gmail node, or return it as an API response in webhook workflows.
For upload presigned URLs, clients post directly to S3 without routing data through n8n. This is essential for user-uploaded content where n8n would become a bandwidth bottleneck:
`javascript
// S3 node: generate presigned upload URL
Operation: Presigned URL
Bucket: user-uploads
Key: {{user_id}}/{{filename}}
Expires: 300
HTTP Method: PUT
ContentType: {{mime_type}}
`
The client uploads directly to the returned URL. A callback webhook notifies n8n when the upload completes, triggering downstream processing.
Event-Driven Workflows with S3 Triggers
S3 events can trigger n8n workflows when files are created or deleted. I set up S3 bucket notifications to send events to an n8n webhook URL:
`javascript
// HTTP Request node: configure S3 notification
Method: PUT
URL: https://my-data-bucket.s3.amazonaws.com/?notificationConfiguration
Body: |
`
When a file lands in the uploads/ prefix, S3 sends an event to n8n’s webhook. The workflow processes the file — perhaps resizing an image, extracting text from a PDF, or running virus scanning — then moves the result to a processed folder.
`javascript
// n8n webhook receives S3 event
// Event body contains: bucket name, object key, event time, size
// Code node: extract file metadata from S3 event
const event = item.json.Records[0].s3;
return [{
json: {
bucket: event.bucket.name,
key: decodeURIComponent(event.object.key),
size: event.object.size,
etag: event.object.eTag.replace(‘”‘, ”),
event_time: event.object[‘sequencer’]
}
}];
`
Connecting to Your Existing Setup
The n8n Docker Deployment guide covers hosting n8n with S3-compatible storage. If you use MinIO for local S3 testing, the connection string replaces the AWS endpoint.
For credential management, the n8n Docker Environment Variables reference explains how to store AWS access keys securely. Never hardcode credentials — use n8n’s encrypted credential store or environment variables.
The n8n Split In Batches node guide pairs well with S3 list operations. Large bucket listings benefit from batch processing to avoid memory issues.
Action Card: Quick S3 Upload Test
Verify your S3 connection with this minimal workflow:
`javascript
// 1. Manual trigger node
// Set: bucket_name = your-test-bucket
// Set: file_key = test/hello.txt
// Set: content = Hello from n8n!
// 2. S3 node: Put Object
// Bucket: {{$json.bucket_name}}
// Key: {{$json.file_key}}
// Content: {{$json.content}}
// 3. S3 node: Get Object
// Bucket: {{$json.bucket_name}}
// Key: {{$json.file_key}}
// 4. Response node: verify content matches “Hello from n8n!”
// 5. S3 node: Delete Object (cleanup)
// Bucket: {{$json.bucket_name}}
// Key: {{$json.file_key}}
`
This confirms upload, download, and delete operations work. Replace the bucket name with your actual S3 bucket.
