mineru-runpod
Guides

Network volumes

Use RunPod network volumes for large input corpora or shared pipeline files, and avoid duplicating model weights already baked into the image.

A RunPod network volume is persistent storage mounted into workers at the same path, usually /runpod-volume. It survives scale-to-zero and is billed separately from GPU compute.

For mineru-runpod, a volume has two practical uses:

  1. Avoid re-downloading large input corpora on each job
  2. Share intermediate or final files between RunPod jobs in a multi-step pipeline

Do not attach a volume only for MinerU's model weights. The published image already contains both model repositories and runs with Hugging Face offline.

Problem 1: pre-staging large input corpora

If you're parsing a fixed collection of documents (a regulatory archive, a books library, customer-supplied PDFs you've already uploaded), uploading each one over file_url or file_b64 on every job wastes time and money:

  • file_url: the worker downloads on each request, adding transfer time and possibly egress charges from the source provider
  • file_b64: base64 expansion leaves roughly 15 MB of raw-file room on /runsync and 7.5 MB on /run

Mount a network volume once, upload the corpus to /runpod-volume/inputs/, and reference each file via volume_path:

{
  "input": {
    "volume_path": "/runpod-volume/inputs/2024-q3-report.pdf",
    "backend": "vlm-auto-engine"
  }
}

No repeated download and no application-level input cap. Workers in the volume's region see the same files.

How to upload to the volume

RunPod gives you two options:

  1. CLI: runpodctl create volume then runpodctl push <local-path> <volume-name>:/<path>
  2. Filesystem pod: spin up a cheap CPU pod with the volume mounted, then scp / rsync from your machine. Tear it down when done.

The filesystem-pod approach is useful for large transfers because it supports familiar tools such as scp and rsync.

Cost trade-off

Compare the current storage price with the transfer time and source-provider egress you avoid. A volume is most useful when several jobs reuse the same large files.

Model weights are already baked in

You don't need to do anything here — both model dependencies (opendatalab/MinerU2.5-Pro-2605-1.2B for the VLM backend and opendatalab/PDF-Extract-Kit-1.0 for the pipeline backend) are baked into the worker image at build time, at /root/.cache/huggingface/. No Cached Models setup, no Network Volume, no runtime download.

If you'd rather slim the image and rely on RunPod's Cached Models feature for the VLM only (which has a single-model dashboard limit), fork the Dockerfile to skip the RUN snapshot_download step. The pipeline backend would then need either a Network Volume or HF_HUB_OFFLINE=0 for runtime downloads.

Problem 2: sharing outputs between jobs

If a downstream pipeline (a follow-up job that does embeddings, indexing, classification) needs to read the parse output, you have three options:

  1. transport: "s3" + S3 bucket — see Output modes. Best for cross-region or multi-tenant pipelines.
  2. transport: "tarball_b64" + caller persists to its own store — fine if the caller already has a place to put things.
  3. Network volume + writes from handler — requires forking the handler to add a write step. Useful for tight self-contained pipelines but adds complexity.

Most users should use option 1. The third option is only worth it when both the producer and consumer of the parse output are RunPod endpoints sharing the same volume.

How to mount a volume

In the RunPod dashboard:

  1. Storage → Network Volumes → New — pick a region (must match the GPU pool your endpoint uses) and a size
  2. Serverless → your endpoint → Edit → Storage — attach the volume; default mount path is /runpod-volume

The volume is read-write by default. Every worker in the endpoint sees the same filesystem state — concurrent writes need standard filesystem-level coordination (lock files, atomic renames, etc.).

What volume_path accepts

The volume_path field of the job input is an absolute filesystem path inside the worker container, resolved against the worker's input roots. It works for:

  • Files on a mounted network volume (/runpod-volume/<anything>, or /workspace/<anything> if you mount it there)
  • Files baked into the Docker image at build time (for example, the fixture used by the Hub validator, under /worker)
  • Files written by an earlier handler step into /tmp (advanced — only if you fork the handler)

Those four directories — /runpod-volume, /workspace, /worker, /tmp — are the defaults. MINERU_VOLUME_ROOTS replaces the list with your own comma-separated absolute paths, either to add somewhere you stage a corpus or to narrow the endpoint to one subtree:

MINERU_VOLUME_ROOTS=/runpod-volume/inputs

The path is resolved before it's read (parent segments collapsed, symlinks followed), so what gets checked is the file that gets opened. Three errors are possible:

ErrorMeaning
volume_path must be an absolute pathA relative path was sent; there is no meaningful working directory to resolve it against
volume_path is outside the configured input rootsThe resolved path landed somewhere the endpoint doesn't serve documents from — check for a typo, or add the directory to MINERU_VOLUME_ROOTS
volume_path not found inside containerThe path is inside a root but no file is there — see Picking a region below, this is the usual symptom of a worker in the wrong region

Picking a region

Network volumes are regional: a volume in one region is not visible to a worker in another. Check current GPU availability for the template's pool list before choosing the volume region.

If your endpoint has multiple regions enabled and you're running on a network volume, pin the endpoint to the volume's region (RunPod dashboard → endpoint → GPU configuration) — otherwise some workers may land in regions without the volume and fail with volume_path not found.

When NOT to use a network volume

  • You parse each document once and discard. Just use file_url — no point paying storage rent.
  • Your input set is small and changes constantly. Inline base64 (file_b64) is fine below the gateway thresholds; use file_url for larger one-off inputs.
  • You only care about cold-start latency. Both MinerU models are baked into the image; a volume for model weights duplicates that work.

Last updated on

On this page