nextflow.config reference

The file scfoundry init writes into the workspace, annotated in full. It is the bundled template with the detected container runtime switched on; edit the workspace copy, never the template.

The complete file

nextflow.config
 1manifest {
 2    name            = 'scFoundry'
 3    description     = 'Deploy, run and evaluate single-cell foundation models'
 4    homePage        = 'https://github.com/Svvord/scFoundry'
 5    mainScript      = 'main.nf'
 6    nextflowVersion = '>=24.10'
 7}
 8
 9// Where user data lives. `scfoundry` sets SCFOUNDRY_WORKSPACE to the workspace created by
10// `scfoundry init`; when Nextflow is run directly from a development checkout the
11// checkout itself is the workspace.
12params {
13    workspace_dir      = System.getenv('SCFOUNDRY_WORKSPACE') ?: "${projectDir}"
14    bin_dir            = "${projectDir}/bin"                          // pipeline code, mounted as /code
15    model_weights_dir  = "${params.workspace_dir}/data/model_weights" // mounted as /data/model_weights
16    cache_dir          = "${params.workspace_dir}/cache"              // container images + Nextflow caches
17    host_side_home_dir = "${params.workspace_dir}/cache/.home"        // HOME seen by the container
18    envs_dir           = "${params.workspace_dir}/envs"
19    gpu_id             = null                                         // e.g. "0" to pin one GPU; null = all visible
20}
21
22// Enable exactly ONE of docker / singularity / apptainer (scfoundry init does this).
23docker {
24    enabled = false
25    runOptions = "--shm-size=16g " + (params.gpu_id ? "--gpus device=${params.gpu_id}" : "--gpus=all") + " -v ${params.bin_dir}:/code -v ${params.model_weights_dir}:/data/model_weights"
26}
27
28singularity {
29    enabled = false
30    pullTimeout = '6h'
31    autoMounts = true
32    runOptions = "--no-home --cleanenv --nv " + (params.gpu_id ? "--env CUDA_VISIBLE_DEVICES=${params.gpu_id} " : "") + "--bind ${params.model_weights_dir}:/data/model_weights --bind ${params.bin_dir}:/code --bind ${params.host_side_home_dir}:${System.getenv('HOME')}"
33    cacheDir = "${params.cache_dir}/.shared/nxf_singularity"
34}
35
36apptainer {
37    enabled = true
38    pullTimeout = '6h'
39    autoMounts = true
40    runOptions = "--no-home --cleanenv --nv " + (params.gpu_id ? "--env CUDA_VISIBLE_DEVICES=${params.gpu_id} " : "") + "--bind ${params.model_weights_dir}:/data/model_weights --bind ${params.bin_dir}:/code --bind ${params.host_side_home_dir}:${System.getenv('HOME')}"
41    cacheDir = "${params.cache_dir}/.shared/nxf_singularity"
42}
43
44conda {
45    enabled = true
46    useMamba = false
47    cacheDir = "${params.cache_dir}/.shared/nxf_conda_envs"
48    createOptions = '-y'
49}
50
51// Remove task work directories once a run completes successfully.
52cleanup = true
53
54// Optional: run GPU/CPU processes through a scheduler, e.g. `scfoundry embed ... --profile slurm`.
55// Uncomment and adapt to your cluster.
56// profiles {
57//     slurm {
58//         process.executor = 'slurm'
59//         process { withLabel: 'gpu_task' { queue = 'gpu'; clusterOptions = '--gres=gpu:1'; time = '12h'; memory = '64 GB' } }
60//         process { withLabel: 'cpu_task' { queue = 'day'; time = '4h'; memory = '32 GB' } }
61//     }
62// }

manifest

Identifies the pipeline and declares the minimum Nextflow version. nextflowVersion '>=24.10' makes an older Nextflow refuse to run rather than fail obscurely.

params block

Setting

Notes

workspace_dir

Taken from SCFOUNDRY_WORKSPACE, which scfoundry exports on every launch. Without it — Nextflow called by hand from a checkout — the pipeline directory itself is the workspace.

bin_dir

Pipeline code, bind-mounted at /code. Always relative to the pipeline, not the workspace, so it follows the installed package.

model_weights_dir

Bind-mounted at /data/model_weights. The natural thing to repoint at shared storage; --weights-dir overrides it per run.

cache_dir

Parent of the image cache and conda cache. Images are large; put this somewhere with room. --cache-dir overrides it per run.

host_side_home_dir

A stand-in $HOME for containers. Because Apptainer runs with --no-home, model code that writes to ~/.cache — Hugging Face, PyTorch Hub — lands here instead of your real home directory.

envs_dir

Declared but never referenced by any task. Safe to ignore.

gpu_id

null exposes every GPU. Set an index to pin one; --gpu overrides it per run.

Runtime blocks

Exactly one of docker, singularity, apptainer should have enabled = true. scfoundry init sets it; scfoundry init --force --runtime docker . changes it.

Option

Why it is set

--shm-size=16g (Docker)

PyTorch dataloader workers communicate through shared memory. Docker’s 64 MB default causes “bus error” crashes with multi-worker loading.

--gpus / --nv

Docker filters devices at the runtime level; Apptainer and Singularity always inject the host driver with --nv and restrict with CUDA_VISIBLE_DEVICES instead. Either way --gpu 0 reaches the container.

--no-home

Stops the container mounting your real home directory, so a model cannot pick up stray dotfiles or conda environments from the host.

--cleanenv

Starts from a clean environment. Prevents host PYTHONPATH or CUDA_VISIBLE_DEVICES leaking in and shadowing the container’s own Python.

autoMounts = true

Lets Nextflow bind the work directory automatically.

pullTimeout = '6h'

Some images are several gigabytes. The default timeout is not generous enough on a slow link.

cacheDir

Where pulled images are stored. Shared between Singularity and Apptainer.

--bind triples

The host–container contract: weights at /data/model_weights, code at /code, and a fake home.

Warning

The home bind uses ${System.getenv('HOME')}, evaluated on the machine that launches Nextflow. If HOME is unset — some batch schedulers do this — the bind target is empty and the run fails with a confusing mount error. Export HOME in your job script.

conda block

Enabled, but inert: no process in the pipeline declares a conda directive. Everything runs in containers. Leave it alone.

cleanup

cleanup = true

Deletes each task’s work directory once the whole run has succeeded. Since every launch has its own run directory, this is what keeps runs/ from growing without bound; a failed run keeps its work directory, which is all --resume needs.

Note

Every launch gets its own run directory under runs/<task>/, and the workspace nextflow.config sets cleanup = true, so the task work directory is deleted once the run succeeds. After a failure it is kept: fix the cause, add --resume to the same command, and Nextflow reuses every task that already completed. scfoundry runs lists the run directories with their status; scfoundry runs --task <task> narrows the list.

Flip it to false before a run whose intermediate files you want to inspect.

profiles

The commented block is a starting point for a Slurm cluster. Uncomment it, adapt queue names and limits, and activate it per run with --profile slurm. Every process in the pipeline carries a gpu_task or cpu_task label, so two withLabel: blocks cover all of them. Running on an HPC cluster discusses the values.

Layering your own settings

Rather than editing the workspace file for every variation, keep changes in a separate file and merge it with --config:

scfoundry embed --method scgpt --data demo/colon_1000.h5ad --config my-cluster.config

Settings in --config override nextflow.config, which in turn overrides module defaults. Command-line parameters beat all of them.

See also