Jesse A. Green / notebook

Fooocus Admin & Developer Guide

Generated June 2026 from lllyasviel/Fooocus at ae05379

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for operators, system administrators, and developers who deploy, harden, extend, or audit Fooocus. It documents the architecture, the complete configuration surface, the security model, operational procedures, and the internal code structure in enough depth to operate Fooocus confidently or rebuild an understanding of it from scratch.

For end-user, task-oriented documentation (installation, generation modes, prompts), see the User Guide.

Note

Fooocus is in limited long-term support (LTS) — bug fixes only, built entirely on Stable Diffusion XL. There are no current plans to migrate to newer architectures. Operationally, this means the codebase is stable and the dependency pins are fixed; the main maintenance burden is keeping the runtime (PyTorch, drivers, NumPy) compatible with newer hardware. This guide flags those points explicitly.


Table of Contents

  1. Executive Summary
  2. Architecture
  3. The Vendored ldm_patched Backend and Monkey-Patching
  4. Requirements and Dependencies
  5. Startup and the Generation Pipeline
  6. Configuration Mastery
  7. Presets
  8. Command-Line Reference
  9. Model Management and Auto-Download
  10. Security Analysis
  11. Deployment
  12. Operations
  13. Repository Structure
  14. Module Reference
  15. Code Quality and Patterns
  16. Potential Improvements
  17. Quick Reference

1. Executive Summary

Fooocus (version 2.5.5 at the documented commit) is a single-process Python application that wraps a Stable Diffusion XL diffusion pipeline behind a Gradio web UI. Its defining characteristic is opinionated automation: a large body of sampling, prompt-expansion, and scheduling logic is applied automatically so that users do not configure the model.

Key architectural facts an operator must know:

  • Single process, single GPU. Fooocus runs one Gradio server and one background worker thread. There is no horizontal scaling primitive; multi-GPU means multiple independent instances.
  • No bundled models. All weights are downloaded on demand from Hugging Face on first run and on preset switches. This is the single largest operational and supply-chain consideration.
  • A vendored, monkey-patched diffusion backend. The ldm_patched/ package is a renamed fork of the ComfyUI backend, and Fooocus patches it at import time (modules/patch*.py, modules/sample_hijack.py). Upgrading the vendored backend can silently break those patches.
  • Auto-update on launch. The recommended entry point (entry_with_update.py) performs a git fetch + hard reset to origin before every run.
  • Minimal but real attack surface. Optional network exposure (--listen, --share), a simple SHA-256 auth file, globally disabled TLS verification, and known community-reported issues (arbitrary code execution via eval(), a path-traversal report) make hardening important when Fooocus is exposed beyond localhost.
                    ┌──────────────────────────────────────────────┐
   Browser  ───────▶│  Gradio server (Blocks, port 7865)           │
                    │   webui.py — UI definition + event wiring     │
                    └───────────────┬──────────────────────────────┘
                                    │ AsyncTask queued
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  Background worker thread (async_worker.py)   │
                    │   process_prompt → diffusion → save_and_log   │
                    └───────────────┬──────────────────────────────┘
                                    │ calls
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  default_pipeline.py  (Fooocus orchestration) │
                    │   patched via modules/patch*.py at import     │
                    └───────────────┬──────────────────────────────┘
                                    │ wraps
                                    ▼
                    ┌──────────────────────────────────────────────┐
                    │  ldm_patched/  (vendored ComfyUI backend)     │
                    │   model_management · samplers · sd · cldm     │
                    └──────────────────────────────────────────────┘

2. Architecture

Fooocus is structured in three layers:

  1. UI layer (webui.py, shared.py, modules/gradio_hijack.py, modules/ui_gradio_extensions.py, javascript/, css/). Defines a single gr.Blocks interface and wires every control to a callback. The interface is queued (.queue()), so generation requests are serialized.

  2. Orchestration layer (modules/). The Fooocus-specific logic: the async task model, prompt processing, style application, the diffusion pipeline orchestration, inpaint/upscale/enhance workflows, LoRA handling, metadata, and the extensive runtime patches applied to the backend.

  3. Backend layer (ldm_patched/). A vendored fork of the ComfyUI diffusion engine providing model loading, memory management, samplers, schedulers, VAE, ControlNet (cldm), and the latent-diffusion model code.

Request lifecycle

  • The user clicks Generate. webui.py:get_task() packs every UI control value (in a fixed positional order) into a worker.AsyncTask.
  • The task is appended to async_worker.async_tasks. A single background worker thread (started at import) picks it up.
  • AsyncTask.__init__ unpacks the positional args into named attributes (this fixed ordering is the contract between webui.py and async_worker.py — see Code Quality).
  • The worker runs the pipeline and yields progress events (preview, results, finish) back to the UI through task.yields, which generate_clicked() consumes in a polling loop.

Concurrency model

There is exactly one worker thread and the Gradio queue serializes requests. Generation is therefore effectively single-task. The --multi-user flag (inherited from the backend) affects storage scoping only, not parallel execution. Interruption (Stop/Skip) is implemented via a backend interrupt_processing mutex.

Important

Because generation is single-threaded and single-GPU per process, a busy instance blocks all users. To serve multiple concurrent users, run multiple instances (each pinned to a GPU with --gpu-device-id) behind a load balancer with sticky sessions.


3. The Vendored ldm_patched Backend and Monkey-Patching

This is the most important architectural fact for anyone maintaining or forking Fooocus.

ldm_patched/ is a vendored, renamed fork of the ComfyUI backend (comfy/). It includes model_management, samplers, sd, controlnet/cldm, k_diffusion, unipc, the latent-diffusion model code (ldm/), and the engine's own argument parser (ldm_patched/modules/args_parser.py).

Fooocus does not modify the backend in place at the call site. Instead, at the moment modules/async_worker.py is imported, it calls patch_all() from modules/patch.py, which monkey-patches functions and methods inside ldm_patched (and a few other libraries) at runtime. The patch modules are:

Module What it patches
modules/patch.py Core diffusion patches: weight calculation, UNet forward, ADM guidance, sharpness, CFG mimicking, sampler hooks. Defines PatchSettings (sharpness, ADM scales, controlnet softness, adaptive CFG).
modules/patch_clip.py Patches CLIP text-encoder behavior.
modules/patch_precision.py Patches numeric precision handling.
modules/sample_hijack.py Replaces/extends the sampling loop (scheduler selection, etc.).
modules/anisotropic.py Anisotropic filtering used by the sharpness patch.

Warning

Upgrading the vendored backend can silently break the patches. Because the patches target specific functions/methods in ldm_patched by name and signature, replacing ldm_patched/ with a newer ComfyUI snapshot — without re-validating every patch — can cause subtle, non-crashing quality regressions (wrong guidance, missing sharpness) rather than loud errors. Treat ldm_patched/ as a pinned, co-versioned component. Re-test image output against known seeds after any backend change.

Note

This is the same hazard class as AUTOMATIC1111's sd_hijack patches over k-diffusion/CLIP. If you maintain a fork, keep a fixed-seed regression suite that compares output images before and after touching the backend or the patch modules.

A practical consequence: the CLI flag surface is split across two parsers. Fooocus's UX flags are defined in args_manager.py; the diffusion-engine flags (VRAM mode, precision, attention implementation, networking) are defined in ldm_patched/modules/args_parser.py. args_manager.py imports the backend parser and adds its own arguments to it, so a single --help shows both. See Command-Line Reference.


4. Requirements and Dependencies

Runtime requirements

Resource Minimum Notes
GPU 4 GB VRAM (NVIDIA) AMD beta (ROCm/DirectML); Intel/Apple via fallbacks
RAM 8 GB + swap 16 GB+ recommended; ≥40 GB free disk per drive if CPUAllocator errors appear
Python 3.10 environment.yaml pins python=3.10
Disk ~10–20 GB for default models, more per preset No models are bundled

Pinned dependencies (requirements_versions.txt)

torchsde==0.2.6                 einops==0.8.0
transformers==4.42.4            safetensors==0.4.3
accelerate==0.32.1              pyyaml==6.0.1
pillow==10.4.0                  scipy==1.14.0
tqdm==4.66.4                    psutil==6.0.0
pytorch_lightning==2.3.3        omegaconf==2.3.0
gradio==3.41.2                  pygit2==1.15.1
opencv-contrib-python-headless==4.10.0.84
httpx==0.27.0                   onnxruntime==1.18.1
timm==1.0.7                     numpy==1.26.4
tokenizers==0.19.1              packaging==24.1
rembg==2.0.57                   groundingdino-py==0.4.0
segment_anything==1.0

PyTorch itself is installed separately by launch.py:prepare_environment(), which defaults to:

pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url https://download.pytorch.org/whl/cu121

Caution

The PyTorch 2.1.0 / CUDA 12.1 pin is the #1 source of "won't run on new hardware" reports. Newer GPUs (e.g. RTX 50-series, compute capability sm_120) are not supported by this build, producing CUDA error: no kernel image is available. Override with the TORCH_COMMAND / TORCH_INDEX_URL environment variables (below) or pre-install a compatible PyTorch before launch.

Note

numpy==1.26.4 is pinned deliberately. Allowing NumPy 2.x into the environment causes numpy.core.multiarray failed to import. Do not blanket-upgrade the environment.

Environment variables that influence installation

Variable Default Effect
TORCH_INDEX_URL https://download.pytorch.org/whl/cu121 PyTorch wheel index.
TORCH_COMMAND pip install torch==2.1.0 torchvision==0.16.0 --extra-index-url $TORCH_INDEX_URL Full torch install command. Override to change torch version.
REQS_FILE requirements_versions.txt Requirements file to install.
XFORMERS_PACKAGE xformers==0.0.23 xformers build (only if xformers install is enabled).
INDEX_URL (empty) Extra pip index URL (modules/launch_util.py).
HF_MIRROR https://huggingface.co Hugging Face mirror for model downloads (also --hf-mirror).
LAUNCH_LIVE_OUTPUT (empty) Stream subprocess output during install.

5. Startup and the Generation Pipeline

Entry chain

entry_with_update.py   → git fetch + (fast-forward) hard reset to origin, then `from launch import *`
   └─ launch.py         → prepare_environment() [pip installs], build_launcher() [writes run*.bat on Windows],
                          parse args, download_models(), then `from webui import *`
        └─ webui.py      → build gr.Blocks UI, start the worker thread, launch the Gradio server (port 7865)
  • entry_with_update.py uses pygit2 to fetch origin and fast-forward the working tree. If you modified files, it prints Update failed - Did you modify any file? and continues with your local code.
  • launch.py sets GRADIO_SERVER_PORT=7865 (if unset), enables the MPS fallback for Apple Silicon, and — notably — sets ssl._create_default_https_context = ssl._create_unverified_context (see Security).
  • build_launcher.py writes run.bat, run_anime.bat, and run_realistic.bat on Windows standalone builds.

The generation pipeline (async_worker.py → default_pipeline.py)

Each AsyncTask is processed roughly as follows:

  1. apply_patch_settings — installs per-process PatchSettings (sharpness, ADM, adaptive CFG) keyed by PID.
  2. Performance overrides — for Extreme Speed / Lightning / Hyper-SD, the worker downloads the acceleration LoRA and forces sampler, scheduler, CFG, sharpness, ADM, and refiner-switch values (set_lcm_defaults, set_lightning_defaults, set_hyper_sd_defaults).
  3. apply_image_input — inspects the active tab and appends "goals" (vary, upscale, inpaint, cn, enhance). Downloads ControlNet / IP-Adapter / inpaint / upscale models as needed.
  4. process_prompt — splits multi-line prompts, applies wildcards (__file__) and arrays ([[a,b,c]]), applies styles, runs Fooocus V2 prompt expansion, encodes positive/negative conditioning via CLIP, and refreshes models/LoRAs.
  5. Diffusion — pipeline.process_diffusion(...) runs the sampler with the chosen steps, switch point (refiner), and resolution.
  6. Post-process — inpaint post-processing, optional NSFW censor (extras/censor.py), then save_and_log writes the image plus a metadata dictionary (prompt, model, seed, sampler, LoRAs, ADM guidance, version, …) to outputs/ via private_logger.

The worker yields preview/results/finish events to the UI throughout.

Note

"Goals" are additive. The Image Prompt tab can mix with Upscale/Variation or Inpaint via the mixing_image_prompt_and_* flags, which is why apply_image_input can append both cn and inpaint.


6. Configuration Mastery

Fooocus configuration is layered. Understanding the precedence is the single most useful operator skill.

Precedence (highest wins)

1. Environment variable matching the config key   (e.g. set `default_cfg_scale` in the env)
2. CLI argument                                    (for the subset exposed as flags, e.g. --output-path)
3. User config file: config.txt                    (JSON; created on first launch)
4. The active preset: presets/<name>.json
5. presets/default.json                            (loaded first as the base)
6. Hard-coded defaults in modules/config.py

modules/config.py loads presets/default.json, then merges config.txt, then merges the active preset, then resolves every key through get_config_item_or_set_default() (which also checks for an environment-variable override and validates the value/type).

config.txt

A JSON file at the repo root (path overridable with the config_path env var). It is created on first launch with the currently-resolved values, and thereafter you edit it to change defaults. Fooocus also always writes config_modification_tutorial.txt — a non-effective tutorial/example file listing every key with its current value and formatting rules.

Tip

Edit config.txt, never config_modification_tutorial.txt. On Windows paths, escape backslashes (\\) and ensure there is no trailing comma before the closing }.

Path configuration

Key Default (relative to repo) Purpose
path_checkpoints ../models/checkpoints/ Base models (list-valued; multiple folders allowed).
path_loras ../models/loras/ LoRA files (list-valued).
path_embeddings ../models/embeddings/ Textual-inversion embeddings.
path_vae ../models/vae/ Standalone VAEs.
path_vae_approx ../models/vae_approx/ Preview approximation VAEs.
path_upscale_models ../models/upscale_models/ Upscaler.
path_inpaint ../models/inpaint/ Inpaint head + patch models.
path_controlnet ../models/controlnet/ ControlNet / IP-Adapter.
path_clip_vision ../models/clip_vision/ CLIP-Vision for image prompt.
path_fooocus_expansion ../models/prompt_expansion/fooocus_expansion GPT-2 expansion model.
path_wildcards ../wildcards/ Wildcard text files.
path_safety_checker ../models/safety_checker/ NSFW safety checker.
path_sam ../models/sam/ Segment Anything models.
path_outputs ../outputs/ Generated images + HTML logs (override with --output-path).

Note

A deprecated user_path_config.txt format is auto-migrated to the new path_* keys at startup (try_load_deprecated_user_path_config), backing up the old file. This is transparent but worth knowing if you inherit an old install.

Generation defaults (selected — full set in modules/config.py)

Key Default Validated range / values
default_model model.safetensors (preset overrides) string
default_refiner None string
default_refiner_switch 0.8 0–1
default_cfg_scale 7.0 (presets lower it) number
default_sample_sharpness 2.0 number
default_sampler dpmpp_2m_sde_gpu must be in sampler_list
default_scheduler karras must be in scheduler_list
default_vae Default (model) string
default_styles ["Fooocus V2","Fooocus Enhance","Fooocus Sharp"] all in legal style names
default_performance Speed one of Performance values
default_max_lora_number 5 ≥1
default_loras_min_weight / max_weight -2 / 2 -10–10
default_aspect_ratio 1152*896 in available_aspect_ratios
default_max_image_number 32 ≥1
default_image_number 2 1–max
default_output_format png png/jpeg/webp
default_clip_skip 2 1–12
default_cfg_tsnr 7.0 number
default_inpaint_engine_version v2.6 None/v1/v2.5/v2.6
default_black_out_nsfw False bool — forces NSFW censoring
default_save_metadata_to_images False bool
default_metadata_scheme fooocus fooocus/a1111
temp_path system temp /fooocus string
temp_path_cleanup_on_launch True bool

Important

Set default_black_out_nsfw: true in config.txt to force the safety checker on for every generation regardless of the per-task checkbox. This downloads and runs stable-diffusion-safety-checker.bin and is the recommended setting for any shared/public deployment.


7. Presets

A preset is a JSON file in presets/ that overrides config keys. The mapping from config key → metadata parameter lives in possible_preset_keys in modules/config.py. Shipped presets:

Preset Base model Refiner CFG Default styles Extra
default juggernautXL_v8Rundiffusion None 4.0 V2 + Enhance + Sharp + SDXL offset LoRA @0.1
anime animaPencilXL_v500 None 6.0 V2 + Semi Realistic + Masterpiece —
realistic realisticStockPhoto_v20 None 3.0 V2 + Photograph + Negative + film LoRA @0.25, strong negative prompt
lcm juggernautXL_v8 None 4.0 V2 + Enhance + Sharp Extreme Speed
lightning juggernautXL_v8 None 4.0 V2 + Enhance + Sharp Lightning
playground_v2.5 playground-v2.5-1024px None 2.0 V2 edm_playground_v2.5 scheduler
pony_v6 ponyDiffusionV6XL None 7.0 Fooocus Pony + dedicated VAE
sai sd_xl_base_1.0 sd_xl_refiner_1.0 @0.75 7.0 V2 + Cinematic + SDXL offset LoRA @0.5

Each preset declares checkpoint_downloads, lora_downloads, vae_downloads, embeddings_downloads (the Hugging Face URLs to fetch) and previous_default_models (fallbacks so a preset switch reuses a model you already have instead of downloading the newest).

Tip

To create a custom edition, copy a preset JSON, point it at your models with their download URLs, and launch with --preset yourname. Setting REWRITE_PRESET = True in config.py (developer-only) makes Fooocus dump the resolved config back to the preset file and exit.


8. Command-Line Reference

Flags come from two parsers. Fooocus-specific flags (args_manager.py):

Flag Type Default Purpose
--share bool off Public Gradio share link.
--preset str None Apply a preset.
--disable-preset-selection bool off Hide in-browser preset dropdown.
--language str default Use language/<x>.json for UI translation.
--disable-offload-from-vram bool off Keep models in VRAM (some Macs need this).
--theme str None light or dark.
--disable-image-log bool off Don't write images/logs to outputs/.
--disable-analytics bool off Disable Gradio analytics.
--disable-metadata bool off Don't embed metadata in images.
--disable-preset-download bool off Skip preset model downloads.
--disable-enhance-output-sorting bool off Don't reorder enhance gallery.
--enable-auto-describe-image bool off Auto-describe when prompt is empty.
--always-download-new-model bool off Download newest preset models (no fallback).
--rebuild-hash-cache int — Regenerate model/LoRA hashes (optional thread count).

Backend/engine flags (ldm_patched/modules/args_parser.py) — selected:

Flag Default Purpose
--listen 127.0.0.1 Bind address (set to 0.0.0.0 to expose).
--port 8188* Server port (*Fooocus sets the Gradio port to 7865 separately).
--web-upload-size 100 Max upload size (MB).
--disable-header-check None Disable host-header check.
--hf-mirror None Hugging Face mirror.
--external-working-path / --output-path / --temp-path / --cache-path None Path overrides.
--in-browser / --disable-in-browser — Auto-open browser.
--gpu-device-id None Select GPU (sets CUDA_VISIBLE_DEVICES).
--all-in-fp32 / --all-in-fp16 — Global precision.
--unet-in-bf16 / --unet-in-fp16 / --unet-in-fp8-e4m3fn / --unet-in-fp8-e5m2 — UNet precision.
--vae-in-fp16 / --vae-in-fp32 / --vae-in-bf16 / --vae-in-cpu — VAE precision/placement.
--clip-in-fp8-e4m3fn / --clip-in-fp8-e5m2 / --clip-in-fp16 / --clip-in-fp32 — Text-encoder precision.
--attention-split / --attention-quad / --attention-pytorch — Attention implementation.
--disable-xformers — Disable xformers.
--always-gpu / --always-high-vram / --always-normal-vram / --always-low-vram / --always-no-vram / --always-cpu — VRAM strategy.
--always-offload-from-vram — Force offload (Fooocus enables this by default unless --disable-offload-from-vram).
--directml — Use DirectML (Windows AMD/Intel).
--disable-ipex-hijack — Disable Intel IPEX hijack.
--pytorch-deterministic — Deterministic mode.
--multi-user — Storage scoping only (not parallel execution).
--debug-mode / --disable-server-log / --disable-server-info — Logging/diagnostics.

Note

Fooocus sets disable_cuda_malloc=True, in_browser=True, and port=None as defaults (in args_manager.py), and computes always_offload_from_vram = not --disable-offload-from-vram. The Gradio server port is 7865 (env GRADIO_SERVER_PORT), distinct from the backend's --port default of 8188.


9. Model Management and Auto-Download

Fooocus downloads models lazily via modules/model_loader.py:load_file_from_url. Triggers and sources:

Trigger Function Source (Hugging Face)
First run / preset model download_models (launch.py) per-preset checkpoint_downloads (e.g. lllyasviel/fav_models, mashb1t/fav_models, stabilityai)
Prompt expansion download_models lllyasviel/misc (fooocus_expansion.bin)
VAE approx (preview) download_models lllyasviel/misc, mashb1t/misc
Inpaint downloading_inpaint_models(v) lllyasviel/fooocus_inpaint (head + inpaint_v{1,25,26}.fooocus.patch)
ControlNet (Canny/CPDS) downloading_controlnet_* lllyasviel/misc
Image Prompt / FaceSwap downloading_ip_adapters(v) lllyasviel/misc (clip_vision, ip-adapter-plus)
Upscaler downloading_upscale_model lllyasviel/misc
Safety checker downloading_safety_checker_model mashb1t/misc
SAM masking download_sam_model mashb1t/misc (vit_b/l/h)
Performance LoRAs downloading_sdxl_{lcm,lightning,hyper_sd}_lora lllyasviel/misc, mashb1t/misc

Caution

No checksum verification. load_file_from_url downloads by URL into the model folder; there is no signature or hash check on the downloaded weights. Combined with the globally-disabled TLS verification (see Security), this means model integrity depends entirely on the Hugging Face source and transport. For air-gapped or high-assurance deployments, pre-stage all models manually, verify hashes out of band, and run with --disable-preset-download.

Model file extensions recognized: .pth, .ckpt, .bin, .safetensors, .fooocus.patch. A hash cache (modules/hash_cache.py) indexes models/LoRAs; rebuild it with --rebuild-hash-cache.


10. Security Analysis

Fooocus is designed as a local, single-user, offline tool. Its defaults are appropriate for localhost use. Exposing it to a network or the internet substantially changes the risk picture. The items below are factual, source-derived, and (where noted) reference public community reports.

Network exposure

  • By default the backend binds 127.0.0.1. --listen (with 0.0.0.0) and --share (a public Gradio tunnel) expose the app.
  • There is no host-header check unless you consider --disable-header-check; Gradio's own protections apply.

Authentication

  • modules/auth.py implements a minimal scheme: an auth.json file (a list of {user, pass} or {user, hash} entries). Passwords are hashed with SHA-256 (no salt, no key-stretching).
  • Auth is only active if auth.json exists; it gates the Gradio app when sharing.
  • The shipped auth-example.json contains the user sitting-duck-1 / password very-bad-publicly-known-password-change-it — a deliberate placeholder.

Warning

If you expose Fooocus with --share or --listen, create a real auth.json with strong credentials. SHA-256 without salting is weak against offline cracking if the file leaks — keep auth.json off any world-readable path and never commit it.

TLS verification disabled globally

launch.py sets:

ssl._create_default_https_context = ssl._create_unverified_context

This disables certificate verification for all HTTPS in the process (model downloads, any outbound call). It exists to avoid corporate-proxy/cert headaches but means downloads are not protected against TLS man-in-the-middle.

Caution

For any hardened deployment, patch this out and verify model integrity by hash. Combined with the no-checksum model download, the unverified TLS context is the most significant supply-chain weakness in the default configuration.

Auto-update trust

entry_with_update.py fetches and hard-resets to origin on every launch. This means each run pulls and executes the latest upstream code. In a controlled environment, launch launch.py directly (not entry_with_update.py) to pin code to a reviewed commit, or run with the network restricted.

Known community-reported issues

Report Summary Operator action
#4185 Arbitrary code execution via eval(). Audit any eval/exec paths before exposing; restrict the OS account Fooocus runs under.
#4156 Path traversal in get_annotated_filepath allowing arbitrary file reads. Do not expose an un-patched instance; run under a low-privilege account with a confined working directory.

Important

These are publicly filed issues against a popular open-source project, not signs of malicious code. The mitigation is standard defense-in-depth: run Fooocus as an unprivileged user, in a container or jailed directory, never as root/Administrator, and never expose an instance directly to the internet without a reverse proxy, authentication, and the hardening above.

Content safety

  • An optional NSFW safety checker (extras/censor.py + stable-diffusion-safety-checker.bin) blacks out flagged images. Enable globally with default_black_out_nsfw: true or per task.

Input handling

  • The Image Prompt, Inpaint, Describe, and Metadata tabs all accept user-uploaded images and (for Metadata) parse embedded parameter strings. Treat uploads as untrusted; --web-upload-size caps upload size.

11. Deployment

Single-instance (typical)

python launch.py --listen --port 7865 --always-normal-vram

Put it behind a reverse proxy (nginx/Traefik/Caddy) terminating TLS, and add authentication (auth.json plus, ideally, proxy-level auth).

Tip

Prefer launch.py over entry_with_update.py in production so the code does not auto-update from upstream on every restart. Pin your checkout to a reviewed commit.

Reverse proxy sketch (nginx)

location / {
    proxy_pass http://127.0.0.1:7865;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;     # Gradio uses websockets
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 600s;                    # long generations
}

Containerized / Colab

  • The repo includes entrypoint.sh (used by container/Colab templates) that symlinks models and outputs to a persistent DATADIR so weights survive container restarts, then runs launch.py.
  • environment.yaml defines a conda env (python=3.10) for reproducible builds.

Multi-GPU / multi-user

Run N instances, one per GPU:

python launch.py --gpu-device-id 0 --listen --port 7865 &
python launch.py --gpu-device-id 1 --listen --port 7866 &

Front them with a load balancer using sticky sessions (a generation streams progress over a persistent connection, so a user must stay pinned to one instance).

Deployment checklist

  • [ ] Run as an unprivileged user, not root/Administrator.
  • [ ] Confine the working directory; mount models read-only where possible.
  • [ ] Create a strong auth.json; never commit it.
  • [ ] Terminate TLS at a reverse proxy; do not rely on --share for anything permanent.
  • [ ] Pre-stage and hash-verify models; consider --disable-preset-download.
  • [ ] Launch launch.py (pinned commit), not entry_with_update.py.
  • [ ] Set default_black_out_nsfw: true for shared instances.
  • [ ] Ensure adequate swap and ≥40 GB free disk per drive.
  • [ ] Confirm PyTorch matches your GPU's compute capability.

12. Operations

Start / stop

  • Start: run.bat (Windows) or python entry_with_update.py / python launch.py.
  • Stop: Ctrl-C the process. The single worker thread and Gradio server terminate with it.

Logs and outputs

  • Generated images and an HTML session log are written under outputs/ (date-stamped). The History Log link in the UI opens it.
  • Console output is the primary diagnostic channel: it prints the resolved args ([System ARGV]), version, model download progress, per-step progress ([Fooocus] ...), and total generation time.
  • --debug-mode, --disable-server-log, --disable-server-info tune verbosity.

Temp management

  • temp_path defaults to the system temp /fooocus. With temp_path_cleanup_on_launch: true (default), Fooocus deletes its temp contents on each launch.

Backup

Back up these, none of which are auto-synced anywhere:

  • config.txt and any custom presets/*.json
  • auth.json
  • models/ (large — or just record the source URLs)
  • outputs/ (your generated work + logs)
  • wildcards/ and sdxl_styles/ if customized

Updating

  • Default: entry_with_update.py pulls on launch.
  • Manual: git pull (or pin to a tag). After updating, re-test output on fixed seeds because of the backend-patch coupling described in §3.

Health check

A simple liveness check is an HTTP GET to the Gradio root on the configured port; a 200 means the server is up. There is no dedicated /health endpoint (Fooocus exposes no REST API — interaction is via Gradio's event protocol).


13. Repository Structure

Fooocus/
├── entry_with_update.py     # Auto-update launcher (git fetch + reset → launch)
├── launch.py                # Environment prep, model download, → webui
├── webui.py                 # Gradio Blocks UI + event wiring (~1500 lines)
├── args_manager.py          # Fooocus CLI flags (extends backend parser)
├── shared.py                # Global gradio_root handle
├── build_launcher.py        # Writes run*.bat on Windows
├── fooocus_version.py       # version = '2.5.5'
├── requirements_versions.txt
├── environment.yaml         # conda env (python=3.10)
├── entrypoint.sh            # container/Colab persistence + launch
├── config.txt               # (generated) user config
├── modules/                 # Fooocus orchestration layer (~29 files)
│   ├── async_worker.py      #   AsyncTask + the worker pipeline
│   ├── default_pipeline.py  #   diffusion orchestration
│   ├── config.py            #   the entire config system
│   ├── flags.py             #   enums: Performance, samplers, schedulers, ratios
│   ├── patch.py             #   core backend monkey-patches
│   ├── patch_clip.py        #   CLIP patches
│   ├── patch_precision.py   #   precision patches
│   ├── sample_hijack.py     #   sampling-loop hijack
│   ├── sdxl_styles.py       #   style loading + application
│   ├── inpaint_worker.py    #   inpaint/outpaint engine
│   ├── upscaler.py          #   upscaling
│   ├── meta_parser.py       #   metadata read/write (fooocus + a1111)
│   ├── private_logger.py    #   image saving + HTML log
│   ├── auth.py              #   SHA-256 auth file
│   ├── model_loader.py      #   load_file_from_url (downloads)
│   ├── lora.py, core.py, util.py, html.py, localization.py, ...
├── ldm_patched/             # Vendored ComfyUI backend (monkey-patched)
│   ├── modules/             #   model_management, samplers, sd, args_parser, ...
│   ├── ldm/                 #   latent diffusion model
│   ├── k_diffusion/, unipc/, controlnet/, t2ia/, taesd/, pfn/, utils/
├── extras/                  # Auxiliary ML: BLIP, GroundingDINO, SAM, facexlib,
│                            #   censor, expansion, interrogate, ip_adapter, preprocessors
├── presets/                 # default/anime/realistic/lcm/lightning/pony_v6/sai/...
├── sdxl_styles/             # JSON style packs (fooocus, sai, mre, twri, diva, ...)
├── wildcards/               # Wildcard text files
├── language/                # UI translation JSON
├── models/                  # (populated at runtime; mostly empty placeholders)
├── javascript/  css/        # Frontend assets injected into Gradio
└── fooocus_colab.ipynb      # Colab notebook

14. Module Reference

Orchestration (modules/)

Module Responsibility
async_worker.py Defines AsyncTask (unpacks ~80 positional UI args into named fields) and the background worker() that runs the full pipeline: prompt processing, goals (vary/upscale/inpaint/cn/enhance), diffusion, censor, save/log. Calls patch_all() at import.
default_pipeline.py Loads/refreshes base+refiner+LoRA+VAE, CLIP encoding, process_diffusion, candidate-VAE selection, expansion. The Fooocus "brain" over the backend.
config.py The complete config system: defaults, validators, env/CLI/file/preset precedence, path resolution, and all downloading_* model fetchers.
flags.py Enums and lists: Performance (+ Steps, StepsUOV, PerformanceLoRA), sampler/scheduler names, aspect ratios, ControlNet types, inpaint options/engines, mask models, metadata schemes, output formats.
patch.py / patch_clip.py / patch_precision.py / sample_hijack.py Runtime monkey-patches over ldm_patched and libraries. PatchSettings holds per-PID sharpness/ADM/CFG.
sdxl_styles.py Loads style JSON packs, normalizes names, applies styles ({prompt} placeholder), wildcard arrays ([[...]]).
inpaint_worker.py The Fooocus-specific inpaint/outpaint algorithm and latent patching.
upscaler.py perform_upscale (ESRGAN-style upscaler).
meta_parser.py Reads/writes generation metadata in fooocus (JSON) and a1111 (plain-text) schemes.
private_logger.py Saves images, embeds metadata, maintains the HTML history log.
auth.py auth.json loading + SHA-256 password check.
model_loader.py load_file_from_url — the download primitive (no checksum).
launch_util.py pip/install helpers, requirements_met, subprocess run.
hash_cache.py Model/LoRA hash index.
localization.py language/*.json UI translation.
gradio_hijack.py / ui_gradio_extensions.py Custom gr.Image component and JS/CSS injection.

Backend (ldm_patched/)

A vendored ComfyUI fork. Key subpackages: modules/ (model_management, samplers, sd, model_patcher, args_parser, ops, sd1_clip), ldm/ (latent diffusion + attention + diffusion modules), k_diffusion/ (sampling), unipc/ (UniPC sampler), controlnet/cldm (ControlNet), t2ia/ (T2I-Adapter), taesd/ (tiny autoencoder previews), pfn/ (upscaler architectures). See §3 for the patching relationship.

Extras (extras/)

Auxiliary ML used by specific features: BLIP + wd14tagger/interrogate (Describe), GroundingDINO + sam + inpaint_mask (text-prompted masking), facexlib + face_crop (FaceSwap), ip_adapter (Image Prompt), preprocessors (Canny/CPDS), censor (NSFW), expansion (Fooocus V2 GPT-2 prompt expansion).


15. Code Quality and Patterns

Strengths

  • Clear three-layer separation (UI / orchestration / backend) keeps Fooocus logic out of the vendored engine.
  • Centralized, validated configuration. Every config key passes through a validator with a typed default, and the precedence chain is consistent. The auto-generated config_modification_tutorial.txt is good operator UX.
  • Opinionated defaults encode substantial domain knowledge (per-preset CFG, styles, ADM guidance) so users get good results without tuning.
  • Pinned dependencies make environments reproducible.

Patterns and risks

  • Positional arg coupling (high-risk). webui.py packs ~80 UI control values into a list in a fixed order, and AsyncTask.__init__ pops them in exactly that order. There is no named-key contract. Any insertion/removal in either file that isn't mirrored in the other silently misaligns every downstream parameter. This is the most fragile seam in the codebase.
  • Monkey-patch coupling to the vendored backend (high-risk). See §3. Quality regressions can be silent.
  • Module-import side effects. Importing async_worker triggers patch_all(); importing config writes files and can prompt interactively (deprecated-config migration). Import order matters.
  • Disabled TLS verification and unchecked downloads (see §10).
  • Large monolith files. webui.py and async_worker.py are each ~1500 lines with deeply nested closures; readable but hard to unit-test in isolation.

Note

The extras/ ML helpers (BLIP, GroundingDINO, facexlib) are themselves vendored third-party code with their own licenses (the repo bundles many LICENSE files, mostly Apache-2.0). Track these for license compliance if you redistribute.


16. Potential Improvements

These are observations for maintainers/forkers, derived from the source:

  1. Replace positional AsyncTask packing with a dataclass / named dict. Eliminates the §15 misalignment hazard and makes the parameter contract explicit and testable.
  2. Add checksum/signature verification to load_file_from_url. Pair each download URL with an expected SHA-256 in the preset JSON and verify after download.
  3. Remove the global ssl._create_unverified_context override or scope it narrowly; rely on proper CA handling with an opt-in escape hatch.
  4. Decouple from PyTorch 2.1.0. Detect GPU compute capability at install time and select a compatible torch build automatically, reducing the dominant class of "won't start on new GPUs" issues.
  5. Provide a pinned-commit production launcher as a first-class, documented path (today operators must know to avoid entry_with_update.py).
  6. A backend-patch regression harness (fixed-seed image diffs) shipped in tests/ would make backend upgrades safe.
  7. Salt the auth hashes and document a secure credential workflow for exposed deployments.

17. Quick Reference

Entry points

File Use
entry_with_update.py Default launcher; auto-updates from origin.
launch.py Direct launcher; no auto-update (prefer in production).
run.bat / run_anime.bat / run_realistic.bat Windows package launchers (preset editions).

Key paths

Path Contents
config.txt User config (JSON).
presets/*.json Editions.
auth.json Credentials (SHA-256).
models/<type>/ Weights (downloaded).
outputs/ Images + HTML logs.
sdxl_styles/*.json Style packs.
wildcards/*.txt Wildcards.
language/*.json UI translations.

Critical environment variables

TORCH_COMMAND, TORCH_INDEX_URL (override torch), HF_MIRROR (model mirror), GRADIO_SERVER_PORT (default 7865), config_path (config location).

Performance ↔ steps ↔ LoRA

Performance Steps UOV steps LoRA
Quality 60 36 —
Speed 30 18 —
Extreme Speed 8 8 LCM
Lightning 4 4 SDXL-Lightning
Hyper-SD 4 4 Hyper-SD

Default ports

Service Port
Gradio UI 7865 (GRADIO_SERVER_PORT)
Backend --port default 8188

Hardening one-liner (exposed instance)

# unprivileged user, pinned code, real auth, NSFW filter on, no preset auto-download
python launch.py --listen --port 7865 --disable-preset-download
# + config.txt: "default_black_out_nsfw": true
# + auth.json with strong credentials, behind a TLS reverse proxy