Nicolas Vannieuwkerke
10/19/2026, 11:07 AMMahesh Binzer-Panchal
10/19/2026, 11:12 AMmeta.id still being there. Going through and fixingNicolas Vannieuwkerke
10/19/2026, 11:12 AMJim Downie
10/19/2026, 11:16 AMNicolas Vannieuwkerke
10/19/2026, 11:19 AMMahesh Binzer-Panchal
10/19/2026, 11:21 AMNicolas Vannieuwkerke
10/19/2026, 11:22 AMNicolas Vannieuwkerke
10/19/2026, 11:22 AMBen Sherman
10/19/2026, 11:28 AMsample += [meta: sample] (set the meta record to the sample record itself)
since meta is typed as Record in the process, nextflow won't try to stage any files in it. it's a bit silly but it works π€·Nicolas Vannieuwkerke
10/19/2026, 11:30 AMMahesh Binzer-Panchal
10/19/2026, 11:34 AMList<Path> , Set<Path>, or Bag<Path> etc?Ben Sherman
10/19/2026, 11:36 AMMahesh Binzer-Panchal
10/19/2026, 11:38 AMList<Path> or Bag<Path> for convenience/referenceNicolas Vannieuwkerke
10/19/2026, 11:38 AMMahesh Binzer-Panchal
10/19/2026, 11:39 AMMahesh Binzer-Panchal
10/19/2026, 11:46 AM4. The output record MUST follow this structure:
- Thefield containing the input identifier from the input recordid
- The optionalThis last bullet point doesn't read well. I'm not quite sure what it meansmetafrom the input record and all other fields should be all possible outputs of the processRecord
Jim Downie
10/19/2026, 11:50 AMNicolas Vannieuwkerke
10/19/2026, 11:51 AMMahesh Binzer-Panchal
10/19/2026, 11:52 AMNicolas Vannieuwkerke
10/19/2026, 11:52 AMBen Sherman
10/19/2026, 11:54 AMDoes the order of files impact the resumability of the process?if you use a List then yes, for Bag and Set no
Ben Sherman
10/19/2026, 11:55 AMNicolas Vannieuwkerke
10/19/2026, 11:56 AMMatthieu Muffato
10/19/2026, 12:15 PMSet but the input record has a List, is there an implicit type conversion ? And is caching done on the list or the set ? (thinking about the resumability)Ben Sherman
10/19/2026, 12:16 PMtoSet()
β’ you can convert Set/Bag to List with toSorted()Ben Sherman
10/19/2026, 12:17 PMAdam Talbot
10/19/2026, 12:32 PMMahesh Binzer-Panchal
10/19/2026, 12:32 PMMahesh Binzer-Panchal
10/19/2026, 12:33 PMMahesh Binzer-Panchal
10/19/2026, 12:34 PMenv and stdout types covered?Nicolas Vannieuwkerke
10/19/2026, 12:35 PMAdam Talbot
10/19/2026, 12:36 PMinput:
MySuperSpecialRecord // instead of record()Adam Talbot
10/19/2026, 12:36 PMNicolas Vannieuwkerke
10/19/2026, 12:37 PMNicolas Vannieuwkerke
10/19/2026, 12:37 PMJim Downie
10/19/2026, 12:37 PMAdam Talbot
10/19/2026, 12:42 PMWe decided against it because of naming collisions with recordsHow so? Because SampleRecord may clash? Note unless you import it, a record is local to the file so I don't know how likely this is
Ben Sherman
10/19/2026, 12:43 PMHow aretyped process hasandenvtypes covered?stdout
env() and stdout() in the output blockBen Sherman
10/19/2026, 12:45 PMMy feeling regarding collection types is that we should stick with Lists for the most partthat seems to be the more common case from what I've seen. I don't think I've needed a
Set<Path> input yet
a counterexample is multiqc, which takes a Bag<Path> since it collects all the upstream outputs with collectBen Sherman
10/19/2026, 12:48 PMNicolas Vannieuwkerke
10/19/2026, 12:49 PMAdam Talbot
10/19/2026, 12:51 PMinput.size == 1 that's less of a concern).
// private record type
record MySampleRecord {
id: String
// stuff
}
process USES_MYSAMPLERECORD {
input:
samples: MySampleRecord
script:
"""
echo 'Hello ${samples.id}!'
"""
}Adam Talbot
10/19/2026, 12:53 PMid as a required field? If I want to refer to a sample as sampleId + treatment + replicate, I can do that now with a meta record π
or too much too soon π
Nicolas Vannieuwkerke
10/19/2026, 12:54 PMsamples.id in your case, id if you used anonymous records)Nicolas Vannieuwkerke
10/19/2026, 12:55 PM'm gonna say something bold...do we needas a required field? If I want to refer to a sample asidsampleId + treatment + replicate
Couldn't you just set the id field to this combination?
Adam Talbot
10/19/2026, 12:56 PMJim Downie
10/19/2026, 1:00 PMBen Sherman
10/19/2026, 1:00 PMCan you type subworkflows anonymously with records, or do we need to make named types?subworkflows should use record types
James Fellows Yates
10/19/2026, 1:01 PMid. As in `id`is the only standard/hardcoded/required one. Everything else is up to pipeline dev. Everything to control the module should come via as an 'input'.Jim Downie
10/19/2026, 1:02 PMsubworkflows should use record typesYes, but do they need to take a named type in order to enforce contents, or can we pass an anonymous function like we do with process inputs?
Nicolas Vannieuwkerke
10/19/2026, 1:20 PMI would use this chance to drop all meta fieldsthat's exactly what we are doing, even
id is technically no longer required in meta and it's become fully optionalNicolas Vannieuwkerke
10/19/2026, 1:20 PMI hate embedding meta data in IDsHow else would you do this in modules without breaking the flexibility?
James Fellows Yates
10/19/2026, 1:22 PMI would use this chance to drop all meta fieldsthat's exactly what we are doing, even id is technically no longer required in meta and it's become fully optional Right. But the first part of my message was a quote from the text. Can I remove 'any other required meta fields like single_end' then?
Nicolas Vannieuwkerke
10/19/2026, 1:23 PMNicolas Vannieuwkerke
10/19/2026, 1:23 PMJames Fellows Yates
10/19/2026, 1:27 PMNicolas Vannieuwkerke
10/19/2026, 1:35 PMNicolas Vannieuwkerke
10/19/2026, 1:37 PMThe `meta` record. This record is used to pass meta data from the input of the module to the output of the module. Content of this record MUST never be used in the process code (but it can however be used in `ext` configuration options by the pipeline developer)Adam Talbot
10/19/2026, 1:38 PMrecord SampleInfo {
id: String
treatment: Treatment
replicate: Int?
}
process DO_STUFF {
input:
record(
meta: SampleInfo,
bam: File,
bai: File
)
script:
def prefix = ext.prefix ?: meta.findAll { it?.trim() }.join('_')
// etc
}Adam Talbot
10/19/2026, 1:39 PMNicolas Vannieuwkerke
10/19/2026, 1:39 PMNicolas Vannieuwkerke
10/19/2026, 1:40 PMBen Sherman
10/19/2026, 2:39 PMYes, but do they need to take a named type in order to enforce contents, or can we pass an anonymous function like we do with process inputs?you can pass an anonymous record. the type checker will verify that it satisfies the record type
Ben Sherman
10/19/2026, 2:42 PMThe `meta` record. This record is used to pass meta data from the input of the module to the output of the module. Content of this record MUST never be used in the process code (but it can however be used in `ext` configuration options by the pipeline developer)
I would only allow ext to be used by a pipeline user at runtime. The developer should never need it because they can do it with workflow logic instead (see #626). It's also easier to compose a pipeline if you don't have all the ext / publishDir config off to the sideNicolas Vannieuwkerke
10/19/2026, 2:43 PMBen Sherman
10/19/2026, 2:44 PMextNicolas Vannieuwkerke
10/19/2026, 2:48 PMAdam Talbot
10/19/2026, 2:59 PMJim Downie
10/19/2026, 3:37 PMIt's also for passing metadata through a pipeline, without having to do a separate -> process -> join loop at every stepWhich could also be avoided if something like this was implemented in Nextflow, which would remove the need for
meta entirely
https://nfcore.slack.com/archives/C07ACNLELR2/p1792161665296959Jonathan Manning
10/20/2026, 9:41 AMJonathan Manning
10/20/2026, 9:44 AMNicolas Vannieuwkerke
10/20/2026, 9:46 AMNicolas Vannieuwkerke
10/20/2026, 9:46 AMAdam Talbot
10/20/2026, 9:48 AMinput:
record(
id: String,
thingy: Thingy, // special thingy type
bam: Path,
bai: Path?
)Nicolas Vannieuwkerke
10/20/2026, 9:51 AMAdam Talbot
10/20/2026, 9:55 AMinput:
record(
id: String,
thingy: List[Thingy], // list of thingy
bam: Path,
bai: Path?
)
Where thingy might have multiple useful things. If we flatten, we get:
input:
record(
id: String,
part_1_of_thingy: List[String],
part_2_of_thingy: List[Int],
part_3_of_thingy: List[Path], // Hope these guys are ordered correctly!
bam: Path,
bai: Path?
)Nicolas Vannieuwkerke
10/20/2026, 9:56 AMAdam Talbot
10/20/2026, 9:57 AMrecord Vcf {
id: String,
vcf: Path,
tbi: Path?
}
...
process COMBINE_VCFS {
input:
record(
id: String,
vcfs: List[Vcf]
)
}Adam Talbot
10/20/2026, 9:57 AMhow would we ever agree on such a structure in nf-core?1. Long arguments on Slack 2. Overly verbose and unproductive pull reviews
Jim Downie
10/20/2026, 10:00 AMAdam Talbot
10/20/2026, 10:17 AMwhere Vcf is definedIn the same file, above the process
does it need to be importedNo
if it's shared among modulesNo, they're just compatibility checks. They're closer to interfaces not types.
are there as many Vcf implementations as there are modules that use ityep. that's fine. doesn't impact anything really.
Jim Downie
10/20/2026, 10:19 AMdoesn't impact anything reallyThat's fine until for one reason or another a particular module uses different field names, or extra field names, etc., right? And then what seemed clean is a bit more complicated and less predictable - you need to read the manual every time
Adam Talbot
10/20/2026, 10:20 AMrecord Vcf {
id: String,
vcf: Path,
tbi: Path?
}
...
process COMBINE_VCFS {
input:
record(
id: String,
vcfs: List[Vcf]
)
}
File 2:
record CompletelyDifferentVcfType {
id: String,
vcf: Path,
tbi: Path?
}
...
process OTHER_VCF_PROCESS {
input:
record(
id: String,
vcf: CompletelyDifferentVcfType
)
}
workflow:
include { COMBINE_VCFS } from '<http://combine_vcfs.nf|combine_vcfs.nf>'
include { OTHER_VCF_PROCESS } from '<http://other_vcf_process.nf|other_vcf_process.nf>' // No type imports!
workflow {
COMBINE_VCFS( ch_vcf.collect() ) // I know this doesn't work but I'm being quick!
OTHER_VCF_PROCESS( ch_vcf )
}Adam Talbot
10/20/2026, 10:21 AMuntil for one reason or another a particular module uses different field names, or extra field names, etc., right?Different is still a problem with flat record types? you're gonna have to
.map.map.map every other line. Extra don't matter, they get ignored.Jim Downie
10/20/2026, 10:22 AMJim Downie
10/20/2026, 10:22 AMJim Downie
10/20/2026, 10:27 AMVcf would be staged?
https://nfcore.slack.com/archives/C07ACNLELR2/p1792409303837149?thread_ts=1792408042.634609&cid=C07ACNLELR2Mahesh Binzer-Panchal
10/20/2026, 10:43 AMAdam Talbot
10/20/2026, 11:07 AMAlso, does the above actually work? It's not clear from what Ben said here if the files inyes. Ben is referring to a bare record where nothing is declared as awould be staged?Vcf
PathBen Sherman
10/20/2026, 11:41 AMRecord is ignored because nextflow can't see the types in it
β’ nested record type like Vcf will have its path fields staged (Path and Path collections)
β’ a collection of record types like List<Vcf> is not staged automatically. you need an explicit stageAs:
input:
record(
id: String,
vcfs: List<Vcf>
)
stage:
stageAs vcfs.collect { v -> v.vcf }, '*'
stageAs vcfs.collect { v -> v.tbi }.findAll { tbi -> tbi != null }, '*'Ben Sherman
10/20/2026, 11:42 AMBen Sherman
10/20/2026, 1:07 PMAdam Talbot
10/26/2026, 12:24 PMBen Sherman
10/26/2026, 12:59 PM