Save VHS Video to S3
Your rendered video is stranded on a rented GPU — this node ships it to S3
- filenames
- files
You just rendered a thirty-second clip on a rented GPU and now it's stuck on a box that dies in an hour. The standard move - render, then manually scp it off - is exactly the kind of busywork this node exists to kill. Save VHS Video to S3 is the handoff: it takes VideoHelperSuite's video filenames and uploads them to your S3 bucket as part of the workflow itself, so the render is archived the second it exists.
It's the most-searched node in KunmyonChoi's ComfyUI_S3_direct, a one-file pack the author calls a "simplified version" of the older kealiu/ComfyUI-S3-Tools. To be clear about what it isn't: it doesn't render anything and it doesn't re-encode. It consumes video that VideoHelperSuite (VHS) already wrote to disk and moves the bytes to the bucket. You still need VHS for the video itself.
How it works
VHS's video-combine nodes emit a filenames output of type VHS_FILENAMES - the list of rendered files. You feed that into this node's filenames input. Internally it loops the list, strips each local path down to the basename, optionally prefixes it and nests it in a folder, then uploads with boto3's client.upload_file(local_path, bucket, key). No re-encode, no local copy kept, no intermediate download. What VHS wrote is what S3 gets, verbatim.
The inputs that matter
- filenames - the
VHS_FILENAMESoutput from a VideoHelperSuite video-combine node. Without VHS installed, this input type doesn't even exist in your graph. - s3_bucket - your bucket. The default
"s3_bucket"is a placeholder; leaving it means nothing uploads. - s3_pathname - an optional folder inside the bucket. Leave it empty and files land at the bucket root; set
renders/2026and you getrenders/2026/myclip.mp4. The code inserts the slash for you, so don't add a trailing one. - s3_file_prefix - a string prepended to the filename with no separator:
final_turnsmyclip.mp4intofinal_myclip.mp4. Useful for stamping a job ID onto everything in one batch.
Optional region, aws_ak, aws_sk cover credentials. The output is files (FILES, a list) - one metadata record per upload with filename, bucket, and pathname. It's marked as an output node, so it terminates that branch of the graph.
Install
The pack plus VHS, which you almost certainly have if you're rendering video:
cd ComfyUI/custom_nodes
git clone https://github.com/KunmyonChoi/ComfyUI_S3_direct
Restart ComfyUI. ComfyUI Manager works too - search "ComfyUI_S3_direct". requirements.txt only pulls torch (already there) and boto3, so boto3 is the one new dependency; Manager installs it for you. No model files.
Credentials and common issues
Credentials resolve env-vars-first (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION), then the node fields, then boto3's default chain (~/.aws/credentials, IAM role). One trap straight from the source: fill in aws_ak without aws_sk and the node silently drops to the default chain instead of telling you it's broken. Also worth knowing: the upload runs inside the node, so a long render means a long tail on the workflow - it'll sit there as long as the network takes per file.
The usual failure modes, in order of likelihood: bucket name is still the s3_bucket placeholder, the credentials chain is empty or half-filled, and VHS was installed after ComfyUI started (restart fixes the missing VHS_FILENAMES type). And the honest limitation: the pack has no endpoint_url parameter, so MinIO, Cloudflare R2, and other S3-compatible services with custom endpoints can't be reached - real AWS S3 is the target.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| filenames | VHS_FILENAMES | — | |
| s3_bucket | STRING | s3_bucket | — |
| s3_pathname | STRING | — | |
| s3_file_prefix | STRING | — | |
| regionopt | STRING | — | |
| aws_akopt | STRING | — | |
| aws_skopt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| files | FILES | — |