Reference · Tools
Upload to Spaces
Uploads a local file to DigitalOcean Spaces
Upload to Spaces sends a file — from disk or from a binary property on the item — to DigitalOcean Spaces and returns the object URL, key and metadata. A typical build is persisting a generated report or image and passing its URL to the message that announces it.
- Node type
- Action (binary)
- Parameters
- 15
- Outputs
- Output, Error
- Credentials
- DigitalOcean Spaces
Upload to Spaces
Upload to cloud storage
Overview
Uploads a local file (e.g., produced by Write to File) or a binary property to DigitalOcean Spaces and stores the object URL + key on the item. Objects are uploaded with a private ACL by default; set ACL to public-read when the returned URL must be fetchable without credentials. Supports expressions like {{ $json.fileWrite.fullPath }}.
Category: Data & Storage
Tool Name: upload_to_spaces
Version: 1
Appearance: Icon: uploadCloud | Color: #0ea5e9
Node Type
Action (Binary) — handles file/binary data operations
Input / Output
| Direction | Port(s) |
|---|---|
| Input | Input |
| Output | Output, Error |
Credentials
This tool requires DigitalOcean Spaces credentials. See the Credentials Guide for setup instructions.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| Spaces Endpoint | string | Yes | https://nyc3.digitaloceanspaces.com | Spaces endpoint URL (region-specific). Example: https://nyc3.digitaloceanspaces.com |
| Spaces Region | string | Yes | nyc3 | Spaces region (e.g., nyc3, sfo3, ams3). |
| Spaces Bucket | string | Yes | — | Bucket name to upload into. |
| CDN Base URL (Optional) | string | No | — | If provided, returned URLs will be built from this base URL instead of https://{bucket}.{region}.digitaloceanspaces.com |
| File Path | string | Yes | {{ $json.fileWrite.fullPath }} | Absolute path to the local file to upload. Typically from write_to_file: {{ $json.fileWrite.fullPath }}. |
| Key Prefix | string | No | uploads | Prefix/folder within the bucket (e.g., uploads, outputs, logs). |
| Key Template | string | Yes | {{ $json.fileWrite.relativePath }} | Object key path (relative) inside the bucket. Supports expressions. Example: {{ $json.fileWrite.relativePath }} |
| ACL | options | No | private | Object ACL. Defaults to “private” for safety; set to “public-read” to allow direct URL fetches. |
Options: private, public-read | ||||
| Content Type Mode | options | No | auto | How to set Content-Type on the upload. |
Options: auto (detected from the file), override | ||||
| Content Type Override | string | No | — | Used only when Content Type Mode = “Override”. Example: text/markdown (shown when Content Type Mode is override) |
| Delete Local File After Upload | boolean | No | false | If true, deletes the local file after a successful upload (useful for ephemeral job/pod storage). |
| Include Input Fields | boolean | No | true | If true, copies the input item JSON into the output item JSON. |
| Result Field Name | string | No | spacesUpload | Where to place upload result metadata on the output JSON. |
| Binary Property | string | No | — | If set, uploads from this binary property instead of file path. Names are case-sensitive — see the upstream node’s Binary Data panel for the exact names to use. File Path is still resolved and sandbox-checked first, so leave it at a valid in-sandbox value. |
| Max Concurrency | number | No | 25 | Maximum number of items to upload concurrently. Range 1–100. |
Output Data
One output item per input item. The upload result is written to the property named by Result Field Name (spacesUpload by default); the rest of the item JSON passes through when Include Input Fields is on, and binary data is forwarded.
{
"spacesUpload": {
"ok": true,
"bucket": "my-bucket",
"key": "uploads/2026/report.pdf",
"url": "https://my-bucket.nyc3.digitaloceanspaces.com/uploads/2026/report.pdf",
"mimeType": "application/pdf",
"sourceFilePath": "…/report.pdf",
"sizeBytes": 84213,
"acl": "private",
"uploadedAt": 1765432100000
}
}
| Field | Meaning |
|---|---|
ok | true on a successful upload |
bucket | The bucket the object was written to |
key | The final object key — Key Prefix joined to the resolved Key Template |
url | URL of the object, built from CDN Base URL when you set one, otherwise from bucket + region. Built from the key, not from the ACL — with the default private ACL this link exists but anonymous fetches of it are refused |
mimeType | The Content-Type stored with the object |
sourceFilePath | The file that was actually sent |
sizeBytes | Size of that file, or null when it could no longer be measured (for example after Delete Local File After Upload removed it) |
acl | The ACL applied to the object |
uploadedAt | Upload time, in epoch milliseconds |
Set Binary Property to upload a file produced by an upstream node instead of one on disk: when the named property is present on the item its contents are uploaded, and otherwise the node falls back to reading File Path.
Reference the result downstream by expression, e.g. {{ $json.spacesUpload.url }}.
Usage Examples
- upload the file to cloud storage
- save the image to Spaces
- push the report to S3
- store the backup in the cloud
- upload results to the bucket
Example Configuration
Basic upload configuration:
{
"id": "upload_to_spaces",
"name": "Upload to DigitalOcean Spaces",
"type": "upload_to_spaces",
"parameters": {
"endpoint": "https://nyc3.digitaloceanspaces.com",
"region": "nyc3",
"bucket": "my-bucket",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyPrefix": "uploads",
"keyTemplate": "{{ $json.fileWrite.relativePath }}",
"acl": "public-read",
"contentTypeMode": "auto"
}
}
Upload with content type override:
{
"id": "upload_to_spaces",
"name": "Upload PDF with Custom Content Type",
"type": "upload_to_spaces",
"parameters": {
"endpoint": "https://sfo3.digitaloceanspaces.com",
"region": "sfo3",
"bucket": "documents-bucket",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyPrefix": "pdfs",
"keyTemplate": "{{ $json.fileWrite.relativePath }}",
"acl": "public-read",
"contentTypeMode": "override",
"contentTypeOverride": "application/pdf"
}
}
Upload with CDN and cleanup:
{
"id": "upload_to_spaces",
"name": "Upload with CDN and Local Cleanup",
"type": "upload_to_spaces",
"parameters": {
"endpoint": "https://ams3.digitaloceanspaces.com",
"region": "ams3",
"bucket": "static-assets",
"cdnUrl": "https://cdn.example.com",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyPrefix": "images",
"keyTemplate": "{{ $now.format('YYYY/MM/DD') }}/{{ $json.fileWrite.filename }}",
"acl": "public-read",
"contentTypeMode": "auto",
"deleteLocalAfterUpload": true,
"resultFieldName": "uploadResult"
}
}
Private upload configuration — private is the default, so ACL is spelled out here only for clarity:
{
"id": "upload_to_spaces",
"name": "Private File Upload",
"type": "upload_to_spaces",
"parameters": {
"endpoint": "https://nyc3.digitaloceanspaces.com",
"region": "nyc3",
"bucket": "private-documents",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyPrefix": "confidential",
"keyTemplate": "{{ $json.fileWrite.relativePath }}",
"acl": "private",
"contentTypeMode": "auto",
"includeInput": false,
"maxConcurrency": 5
}
}
After Write to File — a typical workflow where a file is generated and then uploaded:
{
"nodes": [
{
"id": "write_file",
"name": "Generate Report",
"type": "write_to_file",
"parameters": {
"fileName": "report.pdf",
"content": "{{ $json.report_data }}"
}
},
{
"id": "upload_file",
"name": "Upload to Spaces",
"type": "upload_to_spaces",
"parameters": {
"bucket": "reports-bucket",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyTemplate": "{{ $json.fileWrite.relativePath }}",
"deleteLocalAfterUpload": true
}
}
]
}
Organized storage with date prefixes:
{
"id": "upload_to_spaces",
"name": "Organized Upload",
"type": "upload_to_spaces",
"parameters": {
"bucket": "my-storage",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyPrefix": "{{ $now.format('YYYY/MM') }}",
"keyTemplate": "{{ $workflow.id }}/{{ $json.fileWrite.filename }}",
"contentTypeMode": "override",
"contentTypeOverride": "text/markdown"
}
}
High-volume upload with concurrency control:
{
"id": "upload_to_spaces",
"name": "Batch Upload",
"type": "upload_to_spaces",
"parameters": {
"bucket": "batch-processing",
"filePath": "{{ $json.fileWrite.fullPath }}",
"keyTemplate": "batch-{{ $now.unix() }}/{{ $json.fileWrite.filename }}",
"maxConcurrency": 20,
"deleteLocalAfterUpload": true,
"resultFieldName": "batchUpload"
}
}
Upload from a binary property — uploads the bytes held on the item’s data property rather than a file on disk. Key Template supplies the object name because there is no fileWrite result to borrow one from:
{
"id": "upload_to_spaces",
"name": "Upload Binary Attachment",
"type": "upload_to_spaces",
"parameters": {
"endpoint": "https://nyc3.digitaloceanspaces.com",
"region": "nyc3",
"bucket": "my-bucket",
"binaryProperty": "data",
"keyPrefix": "attachments",
"keyTemplate": "{{ $json.fileName }}",
"acl": "public-read",
"contentTypeMode": "auto"
}
}
Error Handling
| Mode | Behavior |
|---|---|
| stop | Halts workflow on first error |
| continue | Skips failed items, passes successful ones through |
| errorPort | Routes failed items to Error output port |
Tips
Uploads a file from disk, or the bytes on a binary property, to DigitalOcean Spaces (S3-compatible storage) and returns the object URL. Use when you need to persist generated files, images, or data exports to cloud storage. Produces items containing the upload URL, object key, and file metadata. Uploads are private by default — switch the ACL to public-read when the URL has to be fetchable without credentials.
Key Rules and Gotchas
-
ACL defaults to
private. The examples above that omitacl(After Write to File, Organized Storage, Batch Upload) upload private objects. The returnedurlis always built from the key, so it will look like a working link and return an access-denied error to anonymous fetchers. Set"acl": "public-read"whenever the URL is meant to be handed to a browser, an email, or a downstream node that fetches it without credentials. -
Max Concurrency defaults to
25(range 1–100), and the node’s own global cap is 50 concurrent uploads across the whole engine. -
File Path is validated even when Binary Property is set. It must resolve to a non-empty path under
/app/workflow-tmp/,/app/agent_files/or/app/outputs/; anything else fails the item before the upload starts. Its default expression satisfies this, so leave it alone rather than blanking it out for binary uploads. -
Delete Local File After Upload only deletes inside the sandbox. A source outside the allow-list is logged as a warning and left in place — the upload itself still succeeds.
Frequently asked questions
Why is my uploaded file not publicly accessible?
Uploads are private by default. Switch the ACL to public-read when the URL has to be fetchable without credentials — otherwise the returned URL will not work for anonymous visitors.
Where can the file come from?
Either a file on disk or the bytes on a binary property of the incoming item, so it chains after generation, download or conversion steps.
What comes back?
The upload URL, the object key and file metadata, so downstream nodes can both link to and later address the object.
Which credential does it need?
A DigitalOcean Spaces credential.
Build with the Upload to Spaces node
Drop it into a workflow, wire it to an agent, or call it on a schedule. You'll need DigitalOcean Spaces credentials first.
Open BusyBotLast updated . Spotted something wrong? Tell us.