SaveImageToS3
Ship your output straight to S3 (or MinIO) without touching disk
- image
ComfyUI's default Save Image writes a PNG to your hard drive. SaveImageToS3 is for when that's not good enough - when the output needs to land in an S3 bucket instead of on the box running ComfyUI. If your pipeline is "generate here, serve from object storage," this is the node that closes the loop.
It comes from comfyui-tensorops, a small pack by GitHub user un-seen (the repo says "Nodes to perform tensor operations in ComfyUI"). A quick reality check before you commit: the pack is a single commit from October 2024, MIT-licensed, and it's been silent since. It also has a genuinely weird footprint - in mid-2024 ComfyUI Manager started warning about it conflicting with Kijai's popular Florence2 pack, and Kijai's read of the code was that his node names had been copied in. All of that makes it a pack you install because you have a concrete job for it, not one you add for fun.
What it actually does
You feed it an IMAGE tensor (from VAE Decode, Load Image, whatever) and it uploads a WebP copy to your bucket. The object key is built from its two string inputs: {database}/{key}.webp. It stores the first image of a batch at {database}/{key}.webp and then the rest as {database}/{key}-1.webp, -2.webp, and so on. That "no suffix on the first frame" quirk is exactly the kind of detail that bites you later - don't go looking for key-0.webp.
Under the hood it's straightforward: each frame of the tensor is converted to a PIL image, saved to memory as WebP, then pushed with boto3 using an S3 v4 signature and an endpoint_url pulled from the pack's config. The endpoint_url part is why you can point this at MinIO, R2, or any S3-compatible service, not just Amazon proper.
The inputs that matter
- database - a plain STRING, and despite the name it's not a connection selector. It's just the folder/prefix in the object key.
- key - the object name, minus the
.webpextension. - image - the IMAGE to store.
That's it. There are no outputs - it's an output node, so it terminates its branch of the graph.
Installing it
The repo has no README worth the name, so install is the standard two ways. In ComfyUI Manager, search for the pack title comfyui-tensorop (that's the display name - note it, Manager search is picky). Or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/un-seen/comfyui-tensorops
then restart ComfyUI. One warning: this pack's requirements.txt pulls in a whole stack - boto3, redis, surrealist, fal-client, replicate, scipy - even though you only want the S3 node. There's no way to install just one node from it, and every one of those lands in your shared ComfyUI Python environment.
The config trap
All connection details live in nodes/config.py, hardcoded with empty-string defaults. There are no environment variables, no .env file - you edit the Python file:
DATALAKE_AWS_ENDPOINT_URL = "https://minio.example.com"
DATALAKE_AWS_ACCESS_KEY_ID = "your-access-key"
DATALAKE_AWS_SECRET_ACCESS_KEY = "your-secret"
BUCKET = "your-bucket"
Then restart ComfyUI. If those values are still blank when your workflow runs, the upload fails - and here's the sneaky part: the node catches exceptions and logs them (StoreContentError) instead of crashing your prompt. Your workflow will "succeed" while nothing gets stored. When images go missing, check the console log first.
Troubleshooting
- Nothing stored, no error - look at the ComfyUI console; failures are logged, not raised.
- Leaving the endpoint blank means real AWS; filling it in means your S3-compatible service. Pick one and be consistent.
- Your downstream wants PNG - this node only ever writes WebP. Convert after the fact or pick a different path.
One last thing: this is arbitrary Python from a single-commit repo running with your user's permissions, like every custom node. Give the source a skim before you point it at a bucket you care about.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| database | STRING | — | |
| key | STRING | — | |
| image | IMAGE | — |
Outputs (0)
No outputs