Open-Source Wikis

/

ComfyUI

/

Systems

/

Asset system

comfyanonymous/ComfyUI

Asset system

A content-addressed inventory of every model, input, and output ComfyUI knows about. Implemented in app/assets/ and backed by SQLite. Disabled by default; opted in with --enable-assets.

Purpose

Track the files in models/, input/, and output/ so the frontend can:

  • Search and filter by tag, mime type, mtime, or hash.
  • Show previews/thumbnails for outputs.
  • Detect duplicates (same content under multiple paths).
  • Surface system metadata (resolution, duration, sample rate, …) without re-reading every file.

Layout

app/assets/
├── helpers.py              # get_utc_now and friends
├── scanner.py              # 20 KB — walk directories, diff against DB, enqueue work
├── seeder.py               # 29 KB — lifecycle (start, pause, enqueue_enrich, shutdown)
├── api/
│   ├── routes.py           # 28 KB — /assets/* HTTP routes
│   ├── schemas_in.py       # 11 KB — request schemas
│   ├── schemas_out.py      # 2 KB — response schemas
│   └── upload.py           # 6 KB — upload endpoints
├── database/
│   ├── models.py           # Asset, AssetReference, AssetReferenceMeta, AssetReferenceTag, Tag
│   └── queries/            # Read-side queries
└── services/
    ├── ingest.py           # 17 KB — register a single file
    ├── bulk_ingest.py      # 8 KB — batch import
    ├── asset_management.py # 11 KB — resolve hash → path, etc.
    ├── metadata_extract.py # 11 KB — image/video/audio metadata
    ├── hashing.py          # BLAKE3 and SHA helpers
    ├── path_utils.py       # Safe path normalization
    ├── tagging.py          # Tag normalization
    ├── file_utils.py       # I/O helpers
    └── schemas.py          # Internal data classes

Data model

erDiagram
    ASSETS ||--o{ ASSET_REFERENCES : "1..n"
    ASSET_REFERENCES ||--o{ ASSET_REFERENCE_META : "0..n"
    ASSET_REFERENCES ||--o{ ASSET_REFERENCE_TAGS : "0..n"
    TAGS ||--o{ ASSET_REFERENCE_TAGS : "0..n"
    ASSET_REFERENCES ||--o| ASSET_REFERENCES : "preview_id"
Table Key columns Purpose
assets id (uuid), hash, size_bytes, mime_type One row per content-distinct file (deduplicated by hash)
asset_references id, asset_id, file_path, name, owner_id, mtime_ns, enrichment_level, system_metadata, … One row per (path or API-only) reference to an asset
asset_reference_meta (asset_reference_id, key, ordinal) PK + value columns Flexible KV metadata on a reference
asset_reference_tags (asset_reference_id, tag_name) PK + origin Many-to-many tag join
tags name PK + tag_type Tag dictionary

The full schema is in app/assets/database/models.py. Naming conventions are pinned in app/database/models.py so Alembic-generated migrations have stable index/constraint names.

Enrichment levels

Each AssetReference carries an enrichment_level (0/1/2):

  • 0 — basic record only (path + size + mtime).
  • 1 — MIME type and structural metadata read.
  • 2 — full content hash + thumbnail/preview computed.

Background work upgrades references over time so initial scans are fast and the expensive bits happen lazily.

Scanner / seeder

graph LR
    Start[main.py setup_database] -->|--enable-assets| Seeder[asset_seeder.start]
    Seeder --> Scanner[scanner walk]
    Scanner -->|new file| Ingest[services.ingest.register_file_in_place]
    Ingest --> DB[(SQLite)]
    Scanner -->|stale ref| Mark[mark is_missing=true]
    Seeder --> Enrich[enqueue_enrich]
    Enrich --> Hash[hashing + metadata_extract]
    Hash --> DB
    PromptWorker[prompt_worker] -->|asset_seeder.pause / resume| Seeder
    PromptWorker -->|enqueue_enrich roots=output| Seeder

The seeder runs in a background thread (or thread pool, depending on configuration). It pauses while the prompt worker is executing, then resumes between prompts. Output files registered after a prompt completes get an immediate enrichment pass so they become searchable.

asset_seeder.start(roots=("models", "input", "output"), prune_first=True, compute_hashes=True) is the canonical startup call from main.py. Pass is_disabled=True in tests to skip background work.

Ingest

services/ingest.py:register_file_in_place(...) is the single-file entry: given a path, it resolves whether the file already corresponds to an existing Asset (by hash), creates an AssetReference if not, and updates system_metadata from metadata_extract.

bulk_ingest.py batches this for one-shot imports — useful when a user drops a folder of inputs into the UI.

Metadata extraction

services/metadata_extract.py reads:

  • Images — width, height, format, color space (uses PIL).
  • Videos — duration, frame rate, dimensions (uses av).
  • Audio — sample rate, channels, duration.
  • Safetensors — header metadata for model files (architecture hints, license tags, …).

Extracted values land in system_metadata (a JSON column on AssetReference).

REST API

The HTTP routes in app/assets/api/routes.py live behind /assets/.... Notable ones:

  • GET /assets — list with filters (mime, tag, hash, owner)
  • GET /assets/{id}
  • POST /assets/upload — multipart upload
  • PATCH /assets/{id} — update tags or user metadata
  • DELETE /assets/{id} — soft-delete

Schemas are Pydantic in schemas_in.py (request) and schemas_out.py (response). Routes are mounted by register_assets_routes from server.py.

File locking and multi-process

app/database/db.py acquires an OS-level lock on <db>.lock via filelock. If two ComfyUI processes try to share the same DB they get a clear "database is locked" error. Use --database-url to point each process at its own file.

Integration points

  • Bootstrapped in setup_database in main.py.
  • Routes mounted in server.py.
  • _collect_output_absolute_paths in main.py feeds completed prompt outputs into register_output_files (asset-services side) so they become assets immediately.
  • Migrations in alembic_db/versions/.
  • Tested in tests-unit/assets_test/ and tests-unit/seeder_test/, plus tests/test_asset_seeder.py.

Where to start a change

  • Adding a new metadata field: extend AssetReferenceMeta (key/value pattern, no schema change) for free-form fields, or add a column to AssetReference and write an Alembic migration for indexed fields.
  • New REST endpoint: add it to app/assets/api/routes.py; add request/response schemas.
  • New metadata extractor: extend services/metadata_extract.py; add a unit test under tests-unit/assets_test/.
  • New tag origin: extend AssetReferenceTag.origin values and update tagging.py.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Asset system – ComfyUI wiki | Factory