Skip to content

ComfyUI #253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
510b3a9
feat(pkgs): Add new Python package chkpkg_py version 0.5.2
monyarm May 12, 2025
f8dae16
feat(pkgs): Add new Python package colour-science version 0.4.6
monyarm May 12, 2025
c1f6177
feat(pkgs): Add new Python package cstr version unstable
monyarm May 12, 2025
6989581
feat(pkgs): Add new Python package neatest_py version 3.9.1
monyarm May 12, 2025
78fea07
feat(pkgs): Add new Python package img2texture version unstable
monyarm May 12, 2025
1c548d5
feat(pkgs): Add new Python package pixeloe version unstable
monyarm May 12, 2025
3cf610d
feat(pkgs): Add new Python package pilgram version unstable
monyarm May 12, 2025
d20b1ea
feat(pkgs): Add new Python package spandrel version 0.4.1
monyarm May 12, 2025
0ae02b3
feat(pkgs): Add new Python package segment-anything version unstable
monyarm May 12, 2025
1ce7a75
feat(pkgs): Add new Python package transparent-background version uns…
monyarm May 12, 2025
9aaacf3
feat(pkgs): Add ComfyUI frontend package and workflow templates
monyarm May 12, 2025
07bdab8
feat(pkgs): Add Essentials node pack for ComfyUI with necessary depen…
monyarm May 12, 2025
e76af98
feat(pkgs): Add Impact node pack for ComfyUI with necessary dependencies
monyarm May 12, 2025
1b6cf54
feat(pkgs): Add Impact node subpack for ComfyUI with necessary depend…
monyarm May 12, 2025
667ad44
feat(pkgs): Add Inspire node pack for ComfyUI with necessary dependen…
monyarm May 12, 2025
9c9af00
feat(pkgs): Add LJNodes node pack for ComfyUI with necessary dependen…
monyarm May 12, 2025
99919bd
feat(pkgs): Add RGThree Comfy node pack for ComfyUI with necessary de…
monyarm May 12, 2025
abf53f3
feat(pkgs): Add WAS Node Suite for ComfyUI with necessary dependencies
monyarm May 12, 2025
2e58000
feat(pkgs): Add wildcards node for ComfyUI with necessary dependencies
monyarm May 12, 2025
e86b742
feat(pkgs): Add ComfyUI package
monyarm May 12, 2025
c3883ae
refactor(comfyui): Move nodes to comfyui derivation (passthru)
monyarm May 12, 2025
7be8df6
fix(pkgs): Refactor all packages, and make a small fix to comfyui
monyarm May 12, 2025
84839b4
feat(comfyui): Add ComfyUI service module
monyarm May 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions modules/comfyui/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
{ withSystem, ... }:
{
flake.modules.nixos.comfyui =
{
pkgs,
config,
lib,
...
}:
let
cfg = config.services.comfyui;
package = withSystem pkgs.stdenv.hostPlatform.system (
{ config, ... }: config.packages.comfyui.override ({ inherit (cfg) basePath; })
);
in
{
options.services.pyroscope =
with lib;
{
enable = mkEnableOption (lib.mdDoc "ComfyUI");
basePath = mkOption {
type = types.path;
default = "/var/lib/comfyui";
description = "Base path for ComfyUI data.";
};
nodes = mkOption {
type = types.listOf types.package;
default = [ ];
description = "List of custom nodes to install. (Some are defined in comfyui.nodes)";
};
models = mkOption {
type = types.attrsOf types.listOf (
types.either types.package (
types.submodule {
options = {
url = mkOption {
type = types.str;
description = "URL to the model.";
};
hash = mkOption {
type = types.str;
description = "Hash of the model.";
};
name = mkOption {
type = types.str;
default = null;
description = "Filename of the model.";
};
};
}
)
);
default = {
checkpoints = [ ];
clip = [ ];
clip_vision = [ ];
configs = [ ];
controlnet = [ ];
diffusion_models = [ ];
embeddings = [ ];
loras = [ ];
style_models = [ ];
text_encoders = [ ];
upscale_models = [ ];
vae = [ ];
vae_approx = [ ];
};
description = "List of models to install. (Either derivations or sets of urls, hashes and optionally filenames)";
};
port = mkOption {
type = types.port;
default = 8188;
description = "Port for ComfyUI.";
};
listen = mkOption {
type = types.str;
default = null;
description = "Specify the IP address to listen on (default: 127.0.0.1). You can give a list of ip addresses by separating them with a comma like: 127.2.2.2,127.3.3.3 If --listen is provided without an argument, it defaults to 0.0.0.0,:: (listens on all ipv4 and ipv6)";
};
cudaDevice = mkOption {
type = types.str;
default = null;
description = "Set the id of the cuda device this instance will use.";
};
tlsKeyFile = mkOption {
type = types.path;
default = null;
description = "Path to the TLS key file. If set, ComfyUI will use TLS. (Requires tlsCertFile)";
};
tlsCertFile = mkOption {
type = types.path;
default = null;
description = "Path to the TLS certificate file. If set, ComfyUI will use TLS. (Requires tlsKeyFile)";
};
enableCorsHeader = mkOption {
type = types.either types.str types.bool;
default = false;
description = "Enable CORS (Cross-Origin Resource Sharing) with optional origin or allow all with default '*'.";
};
maxUploadSize = mkOption {
type = types.int;
default = 0;
description = "Maximum upload size in MB. 0 means no limit.";
};
cudaMAlloc = mkOption {
type = types.bool;
default = true;
description = "Enable cudaMallocAsync (enabled by default for torch 2.0 and up).";
};
deterministic = mkOption {
type = types.bool;
default = false;
description = "Enable deterministic mode (default: false).";
};
}
// builtins.listToAttrs (
map
(x: {
name = "${x}Path";
value = mkOption {
type = types.path;
default = "${cfg.basePath}/${x}";
description = "Path for ComfyUI ${x} data.";
};
})
[
"models"
"input"
"output"
"temp"
"user"
]
);
config =
with lib;
with builtins;
{
assertions = [
{
assertion = (isNull cfg.tlsKeyFile) != (isNull cfg.tlsCertFile);
message = "If tlsKeyFile is set, tlsCertFile must also be set and vice versa.";
}
];
systemd.services.pyroscope = lib.mkIf cfg.enable {
description = "comfyui";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart =
"${getExe package} --multi-user --port ${toString cfg.port}"
+ (optionalString (!isNull cfg.listen) " --listen ${cfg.listen}")
+ (optionalString (!isNull cfg.cudaDevice) " --cuda-device ${cfg.cudaDevice}")
+ (optionalString (!isNull cfg.tlsKeyFile) " --tls-keyfile ${toString cfg.tlsKeyFile}")
+ (optionalString (!isNull cfg.tlsCertFile) " --tls-certfile ${toString cfg.tlsCertFile}")
+ (optionalString (cfg.enableCorsHeader != false) (
" --enable-cors-header"
+ (
if isString cfg.enableCorsHeader then
cfg.enableCorsHeader
else if cfg.enableCorsHeader == true then
"*"
else
""
)
))
+ (optionalString (cfg.maxUploadSize != 0) " --max-upload-size ${toString cfg.maxUploadSize}")
+ (if cfg.cudaMAlloc then " --cuda-malloc" else " --disable-cuda-malloc")
+ (optionalString cfg.deterministic " --deterministic");
};
};
};
};
}
1 change: 1 addition & 0 deletions modules/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
./random-alerts
./host-info.nix
./secrets.nix
./comfyui
];
}
56 changes: 56 additions & 0 deletions packages/comfyui/base.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
version,
modelPathsFile,
modelsPath,
inputPath,
outputPath,
tempPath,
userPath,
stdenv,
fetchFromGitHub,
}:
stdenv.mkDerivation {
pname = "comfyui-base";
inherit version;

src = fetchFromGitHub {
owner = "comfyanonymous";
repo = "ComfyUI";
rev = "b685b8a4e098237919adae580eb29e8d861b738f";
hash = "sha256-OtTvyqiz2Ba7HViW2MxC1hFulSWPuQaCADeQflr80Ik=";
};

installPhase = ''
runHook preInstall
echo "Preparing bin folder"
mkdir -p $out/bin/
echo "Copying comfyui files"
# These copies everything over but test/ci/github directories. But it's not
# very future-proof. This can lead to errors such as "ModuleNotFoundError:
# No module named 'app'" when new directories get added (which has happened
# at least once). Investigate if we can just copy everything.
cp -r $src/app $out/
cp -r $src/api_server $out/
cp -r $src/comfy $out/
cp -r $src/comfy_api_nodes $out/
cp -r $src/comfy_extras $out/
cp -r $src/comfy_execution $out/
cp -r $src/utils $out/
cp $src/*.py $out/
cp --remove-destination $src/folder_paths.py $out/
cp $src/requirements.txt $out/
mv $out/main.py $out/comfyui
echo "Copying ${modelPathsFile} to $out"
cp ${modelPathsFile} $out/extra_model_paths.yaml
echo "Setting up input and output folders"
ln -s ${inputPath} $out/input
ln -s ${outputPath} $out/output
echo "Setting up node folders"
ln -s ${modelsPath}/wildcards $out/wildcards
mkdir -p $out/${tempPath}
echo "Patching python code..."
substituteInPlace $out/folder_paths.py --replace 'os.path.join(base_path, "temp")' '"${tempPath}"'
substituteInPlace $out/folder_paths.py --replace 'os.path.join(base_path, "user")' '"${userPath}"'
runHook postInstall
'';
}
141 changes: 141 additions & 0 deletions packages/comfyui/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
lib,
runCommand,
callPyPackage,
writers,
writeTextFile,
pkgs,
basePath ? "/var/lib/comfyui",
modelsPath ? "${basePath}/models",
inputPath ? "${basePath}/input",
outputPath ? "${basePath}/output",
tempPath ? "${basePath}/temp",
userPath ? "${basePath}/user",
customNodes ? [ ],
models ? {
checkpoints = [ ];
clip = [ ];
clip_vision = [ ];
configs = [ ];
controlnet = [ ];
embeddings = [ ];
upscale_modules = [ ];
vae = [ ];
vae_approx = [ ];
gligen = [ ];
},
}:

let
version = "unstable-2025-04-26";

config-data = {
comfyui = {
base_path = modelsPath;
checkpoints = "${modelsPath}/checkpoints";
clip = "${modelsPath}/clip";
clip_vision = "${modelsPath}/clip_vision";
configs = "${modelsPath}/configs";
controlnet = "${modelsPath}/controlnet";
diffusion_models = "${modelsPath}/diffusion_models";
embeddings = "${modelsPath}/embeddings";
loras = "${modelsPath}/loras";
style_models = "${modelsPath}/style_models";
text_encoders = "${modelsPath}/text_encoders";
upscale_models = "${modelsPath}/upscale_models";
vae = "${modelsPath}/vae";
vae_approx = "${modelsPath}/vae_approx";
};
};

modelPathsFile = writeTextFile {
name = "extra_model_paths.yaml";
text = (lib.generators.toYAML { } config-data);
};

pythonEnv = callPyPackage ./python-env.nix {
inherit customNodes;
};

installedModels =
let
# Helper function to process a single category
processCategory =
category: urls:
map (
model:
if lib.isDerivation model then
model
else
pkgs.fetchurl rec {
url = model.url;
name = if model.name != null then model.name else builtins.baseNameOf model.url;
hash = model.hash;
downloadToTemp = true;
recursiveHash = true;
postFetch = ''
echo mkdir -p "$out"/${category}
mkdir -p "$out"/${category}
cp "$downloadedFile" "$out"/${category}/${name}
'';
}
) urls;
in
builtins.concatLists (builtins.attrValues (builtins.mapAttrs processCategory models));

comfyui-base = callPyPackage ./base.nix {
inherit
version
modelsPath
modelPathsFile
inputPath
outputPath
tempPath
userPath
;
};

wrapperScript = writers.writeBashBin "comfyui" ''
cd $out
export WAS_CONFIG_DIR="${userPath}"
${pythonEnv}/bin/python comfyui \
--input-directory ${inputPath} \
--output-directory ${outputPath} \
--extra-model-paths-config ${modelPathsFile} \
--temp-directory ${tempPath} \
"$@"
'';

in
(runCommand "comfyui"
{
inherit version;

meta = {
homepage = "https://github.com/comfyanonymous/ComfyUI";
description = "The most powerful and modular stable diffusion GUI with a graph/nodes interface.";
license = lib.licenses.gpl3;
platforms = lib.platforms.all;
};
passthru.nodes = import ./nodes { inherit callPyPackage; };
}
(
''
mkdir -p $out/{bin,custom_nodes,models}
''
+ (lib.concatMapStrings (dir: ''
[[ ${dir.pname} == "was-node-suite" ]] && mkdir -p $out/custom_nodes/was-node-suite
cp -r ${dir}/* $out/
'') ([ comfyui-base ] ++ customNodes))
+ (lib.concatMapStrings (model: ''
cd ${model}
find . -mindepth 1 -type d -exec mkdir -p $out/models/{} \;
cp -rs ${model}/* $out/models/
'') installedModels)
+ ''
cp ${wrapperScript}/bin/comfyui $out/bin/comfyui
chmod +x $out/bin/comfyui
substituteInPlace $out/bin/comfyui --replace "\$out" "$out"
''
)
)
11 changes: 11 additions & 0 deletions packages/comfyui/nodes/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{ callPyPackage }:
{
wildcards = callPyPackage ./wildcards.nix { };
impact-pack = callPyPackage ./impact-pack.nix { };
# impact-subpack = callPyPackage ./impact-subpack.nix { }; # can't find ultralytics
rgthree-comfy = callPyPackage ./rgthree-comfy.nix { };
essentials = callPyPackage ./essentials.nix { };
inspire-pack = callPyPackage ./inspire-pack.nix { };
ljnodes = callPyPackage ./ljnodes.nix { };
was-node-suite = callPyPackage ./was-node-suite.nix { }; # needs directory to be writeable, and opencv with ffmpeg
}
Loading