Upload to GCS πͺ£
This GCS uploader node is built for one pipeline β check if it's yours
- image
- gcs_url
Let's be honest about this one up front: "Upload to GCS πͺ£" is not a general-purpose uploader that any ComfyUI user needs. It's a bespoke piece of one specific product - an "AI Influencer" SaaS that generates images on a RunPod-hosted ComfyUI and files them into a Supabase + Google Cloud Storage backend. The author wrote it to serve their own pipeline, it's a single-commit repo with essentially zero community footprint, and if you're not running that exact stack, the node will politely do nothing useful for you.
But if you are building the same shape of thing - ComfyUI headless on a rented GPU, a database telling it what to make, and finished images that need to land in object storage - it's a genuinely neat reference for a real problem. So here's what it actually does and how to make it work.
The mechanism (and the part worth stealing)
The whole pitch is one line from the README: zero Supabase Egress cost. The naive architecture routes generated images from your GPU box through a Supabase Edge Function into GCS, which bills you for ~4MB of egress per image. This node cuts that by uploading the pixels directly from ComfyUI to GCS, then sending only a small URL string to Supabase. Egress ~0. It's the same "the API node just sends a URL" pattern you see elsewhere in the ecosystem, but pointed at your own infra instead of a model vendor.
Under the hood it does five things in GCSUploadNode.upload():
- Loads
config.jsonfrom the node's own directory for your Supabase URL + service role key. - Fetches GCS credentials at runtime from your
system_configstable (set in the web dashboard, not in the repo - that's why there's only one local config file). - Converts the image tensor to PNG bytes.
- Uploads to
images/{content_item_id}/{image_type}/{job_id}_{slot_index}.pngin your bucket. - Upserts a row into
generated_images, marks the jobCompletedinproduction_jobs, and logs tosystem_logs. On any failure it flips the job toFailedwith the error message.
The output is a single string, gcs_url, the public https://storage.googleapis.com/<bucket>/<path> - the thing your frontend or DB actually stores.
The inputs that matter
All five inputs are required, and honestly, three of them are boring plumbing:
image(IMAGE) - the tensor from your KSampler/VAE Decode. Note it grabsimage[0]only, so in a batch of more than one frame, only the first frame gets uploaded. Fine for a content pipeline that generates one slot at a time.job_idandcontent_item_id(STRING) - theproduction_jobs.idandcontent_items.idfrom your Supabase. These get injected per-run, typically by a String Literal / Load Text node or straight into the prompt payload when your system queues the job. The DB writes are keyed on them, so they're the fields you actually have to get right.image_type(SFW/NSFW) andslot_index(INT, 0β16) - where in the product the image goes.slot_indexjust lands in the filename.
Installing it
ComfyUI Manager β Install via Git URL β https://github.com/sumethweer-cmd/comfyui-gcs-uploader, or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/sumethweer-cmd/comfyui-gcs-uploader
pip install -r comfyui-gcs-uploader/requirements.txt
Restart ComfyUI, then copy the config:
cd ComfyUI/custom_nodes/comfyui-gcs-uploader
cp config.json.example config.json
config.json is gitignored, so your key won't leak into a push. The dependencies are light - google-cloud-storage, requests, pillow - no model downloads, nothing heavy.
Where you'll get burned
The failure modes are all "bespoke pipeline" failures, and the code is honest about them:
- No
config.jsonβ it raisesFileNotFoundErrorand tells you to copy the example. That's your first stop on any failure. - Missing GCS keys in
system_configsβ explicitValueErrornaming exactly which of the four (project ID, client email, private key, bucket name) is missing. The dashboard credentials have to be there, because there's no fallback. - Your Supabase tables must exist with the expected schema -
production_jobs,generated_images,system_configs,system_logs. This node doesn't create them. - The service role key in
config.jsonbypasses Row Level Security. That's a very privileged credential sitting in a file on your GPU box. Read the pack's source before running it anywhere you don't fully trust - a node that holds a key and phones home by design is exactly the category that's been weaponized before, so treat any fork of this the way you'd treat a sketchy API pack.
If you're not running the AI Influencer stack, skip it - but if you're wiring ComfyUI output straight into object storage, this is a clean, readable blueprint for doing it right.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| job_id | STRING | β | |
| content_item_id | STRING | β | |
| image_type | COMBO | 2 options: SFW, NSFW | |
| slot_index | INT | 00β16 | β |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| gcs_url | STRING | β |