November 01, 2026
A custom file node that reads D:/Projects/Show_A/plates/sh010/ or /Volumes/Edit/Show_A/ stops working the moment the graph runs on a Linux GPU server, because neither the drive letter nor the macOS mount exists there. The fix is to replace every absolute path with one asset root plus the project-relative path you already use, recreate that tree in cloud storage, and carry your access rules over as tests you run before the first production render. On GMI Cloud, GMI Studio runs ComfyUI-based workflows with custom nodes and private logic on dedicated GPUs, its storage keeps input and output folders that persist across runs, and Studio Enterprise adds RBAC with usage visibility for teams that assign roles per person.
Client-confidential media can run in your own ComfyUI build on GMI's bare-metal servers inside an isolated VPC, or on containers whose inbound sources are limited by firewall rules you define.
Absolute paths hide in more places than the node source. Search all of these:
\\ or /.extra_model_paths.yaml and any environment variables your launch scripts set.Record each one in a table like this, using your own values:
| Field | Example entry |
|---|---|
| Local path | D:/Projects/Show_A/plates/ |
| Used by | Custom "Load Plate Sequence" node, two saved workflows |
| Content | EXR plates, roughly 2 TB (assumed for this example) |
| Sensitivity | Client-confidential, unreleased |
| Readers and writers | Comp team reads, render jobs write |
| Cloud target | Dedicated GPU lane, /mnt/film/Projects/ |
Two Linux details catch Windows and macOS teams. Paths are case-sensitive, so SH010.exr and sh010.exr become two different files, and a node that worked with mixed case locally will miss files. A backslash is an ordinary filename character on Linux, so parse each Windows path as a Windows path first (Python's PureWindowsPath does this), drop the drive letter or share root, and keep only the project-relative part.
In your own ComfyUI build on a GMI container or bare-metal server, change each file node to resolve paths as ASSET_ROOT plus a relative path, and store only the relative part in workflow widgets. The node reads the root from an environment variable set in your launch script or image, so the same graph runs on a Windows workstation, a Mac, or the GPU server once each machine sets its own root.
| Role | Windows workstation | macOS workstation | Dedicated GPU lane |
|---|---|---|---|
| Asset root | D:/Projects/ |
/Volumes/Edit/Projects/ |
/mnt/film/Projects/ |
| Model root | D:/ComfyUI/models/ |
/Volumes/Edit/models/ |
/mnt/models/ |
| Render output | D:/Projects/<show>/renders/ |
/Volumes/Edit/Projects/<show>/renders/ |
/mnt/film/Projects/<show>/renders/ |
ComfyUI itself can follow the same map. extra_model_paths.yaml points model folders at the model root, and ComfyUI's command-line options include --input-directory and --output-directory for moving the default input and output folders. Sidecars follow the same rule: OpenColorIO locates its config through the OCIO environment variable and can resolve LUTs relative to the config file, so a config kept under the asset root, with its LUTs beside it and its search paths written as relative paths, moves without edits once OCIO points at its new location. Configs with absolute search paths, EDLs, and shot lists get the same prefix rewrite as workflow JSON.
Inside Studio, workflows reference files by their folder in Inference Storage. gmi-studio-input holds assets your workflows reference, gmi-studio-output receives media written back by runs, and New Folder recreates the show, sequence, and shot tree there, so each file keeps the names it had on the NAS.
For the dedicated lane, run a resolver script over every saved workflow at two points. Before the sync, it rejects absolute paths and .. segments, finds each input in the local tree, and flags case mismatches; a non-zero exit stops the sync. After the sync, it joins each relative path to the cloud root, resolves symlinks, confirms the result still sits under that root, and checks that the file arrived; a non-zero exit there holds back the first render. Render output paths skip only the file check, since those files do not exist yet, and still need a folder under the root that ComfyUI's account can write to; a sequence written with a frame token such as %04d or #### is checked for every frame in the range the node will read.
Pick a lane for each class of media based on the sensitivity column of your inventory.
Studio storage lane. Upload Files accepts multi-file uploads into the folder tree, and the header shows usage against your quota. Files in Inference Storage, and outputs written to gmi-studio-output, are served from hosted URLs that can be passed to endpoints taking an image or video input, and the Upload API returns a public URL for jpeg, png, mp4, mp3, and wav files. This lane suits reference frames, look-dev stills, and other media cleared for link-based access. Results come back through a Save node (Save Image, Save Audio, or Save Video), and My Media lets you preview or download every output without re-running the graph.
Dedicated GPU lane. EXR plates, unreleased footage, anything under a client NDA, and the render sequences made from them go here: run your own ComfyUI build on a GMI container or bare-metal server and sync both directions over SSH. Containers launched from GMI's official templates expose SSH on port 22, and a custom template can map its own ports or use the browser-based web shell. Reconfiguring a container replaces everything inside it, so treat its working tree as a rebuildable copy: renders sync back through the return manifest before any reconfigure, and the local NAS stays the master.
For both lanes, write a manifest per transfer listing relative path, size, and SHA-256, and compare it after upload and again when renders return. Renders come back through the same path map in reverse, so renders/sh010/v003/ lands in the same relative place on the local NAS.
A NAS share bundles several kinds of permission into one setting. Map each kind separately before cutover.
| What the control decides | Local control | Counterpart on GMI |
|---|---|---|
| Who belongs to the team | NAS accounts and groups | Organization membership (invite, remove) |
| Who can change a workflow or only open it | Write access to the shared workflow folder | Studio Team Space Can edit and Can view, plus Studio Enterprise RBAC |
| Who can read or write plate files on the GPU host | Share and folder ACLs | Linux users, groups, and directory permissions applied to the account ComfyUI runs as, set with full root access on bare metal or in your container image |
| Which networks can reach the host | VPN-only access to the file server | Firewall inbound rules limited to your office or VPN CIDR blocks |
| Which machines share a network | Isolated render VLAN | VPC and subnets for bare-metal servers |
| Who can open a file by link | Shared-link policy | Hosted URLs in the Studio lane, used only for media cleared for links |
On a container's public IP, an Elastic IP passes no inbound traffic until a firewall is attached, and that firewall's rules decide which sources and ports get through. On the host itself, file permissions protect plates only for the account that actually reads them, so run ComfyUI under a non-root service account in the plate group, and give teams that must stay apart their own instances.
Then run deny tests and record each result with a date:
With the local ComfyUI install, models, and launch settings left in place, falling back means pointing ASSET_ROOT, the model root, and OCIO at their local paths again. Keep the local tree read-only during the migration window so nothing diverges, and sync any cloud renders back through the return manifest before reopening it for writes. Agree on rollback triggers in advance, such as a resolver run with a non-zero exit, a failed deny test, or a checksum mismatch on returned renders.
Give them their own root. Weights change on a different schedule than shots and are shared across shows, so a separate model root, set through a variable you define such as MODELS_ROOT and mapped through extra_model_paths.yaml, lets you update them without touching project folders.
Choose a cut-over point per sequence rather than per show. Finish in-flight versions locally, copy the sequence with its manifest, run the resolver and deny tests, and then render the next version in the cloud. Earlier versions stay where they are until the whole show has moved.
For a film team choosing where private workflows and custom file nodes will run across dedicated GPUs, a dry run on one sequence answers the question with your own files. Create the Studio folder tree in Inference Storage from the GMI console, run the resolver against the dedicated-lane tree, and bring the results to our team when you are ready to size dedicated GPUs and RBAC under Studio Enterprise.
Colin Mo
GMI Cloud helps you architect, deploy, optimize, and scale your AI strategies
