Skip to content

Workflow outputs in Side Quests#884

Open
vdauwera wants to merge 5 commits intomasterfrom
gvda-workflow-outputs-in-sidequests
Open

Workflow outputs in Side Quests#884
vdauwera wants to merge 5 commits intomasterfrom
gvda-workflow-outputs-in-sidequests

Conversation

@vdauwera
Copy link
Collaborator

@vdauwera vdauwera commented Feb 12, 2026

1. Essential Scripting Patterns

  • Scripts: Removed publishDir from modules/generate_report.nf (both starter and solution). Added publish:/output {} to solution main.nf, publishing reports to results/reports/.
  • Docs: Removed publishDir line from the GENERATE_REPORT process code block. No narrative changes needed since publishDir wasn't discussed in the lesson text.

2. Metadata

  • Scripts: Removed publishDir from modules/cowpy.nf in starter, solution/3.2, and solution/3.3. Added publish:/output {} to both solution main.nf files, publishing to results/.

  • Docs: Removed publishDir line from the COWPY process code block. No narrative changes needed.

3. Dev Environment + IDE Features

  • Scripts: Removed publishDir from basic_workflow.nf, modules/fastqc.nf, modules/star.nf, modules/utils.nf (MULTIQC and CUSTOM_DUMPSOFTWAREVERSIONS), and complex_workflow.nf (TRIM_GALORE and FEATURECOUNTS). Added publish:/output {} to both basic_workflow.nf and complex_workflow.nf. Added fastqc, trimmed, and alignments to the RNASEQ_PIPELINE named workflow's emit: section so the entry workflow can publish them.

  • Docs: Removed publishDir from the "Before" code block showing the inline FASTQC process. Changed the project-wide search example from searching for publishDir to searching for container.

4. Debugging

  • Scripts: Removed publishDir from all three processes in both buggy_workflow.nf (starter with bugs intact) and solutions/buggy_workflow.nf. Added publish:/output {} to both, publishing to processed/, heavy/, and files/ subdirectories under params.output.

  • Docs: Updated the "Complete Corrected Workflow" solution code block to match: removed publishDir from all three processes, added publish:/output {} blocks.

5. nf-test

  • Scripts: Removed publishDir from both sayHello and convertToUpper processes. Added publish:/output {} publishing to results/. Test assertions checking $launchDir/results/ are unchanged since the output directory is still results/.

  • Docs: Updated the expandable workflow code block to match. No changes to test assertion code or prose about "published to a directory called results/".

6. Workflows of Workflows

  • Scripts only (no doc references to publishDir). Removed publishDir from say_hello.nf, say_hello_upper.nf, and reverse_text.nf in both starter and solution directories. Added publish:/output {} to solution main.nf, publishing greetings, upper, and reversed outputs to results/.

7. Working with Files

  • Scripts: Removed publishDir from modules/analyze_reads.nf (starter and solution). Changed process output from val(meta.id) to val(meta) so the output block can use metadata for dynamic paths. Added publish:/output {} to solution main.nf with a path closure: { meta, file -> "${meta.type}/${meta.id}/${meta.replicate}" }.

  • Docs (most extensive changes):

    • Section 6.1: Removed publishDir from process code block, removed #!/usr/bin/env nextflow shebang (module file), changed output to emit full meta. Replaced the note about publishDir and tag closures with a note about tag closures only.
    • Section 6.2.2: Expanded the After/Before blocks to show the full workflow with main:/publish: sections and the output {} block. Added explanatory text about how publish: and output {} work together.
    • Section 6.4: Changed Before/After from modifying publishDir in the module to modifying the path closure in the output {} block.
    • Takeaway: Changed "publishDir directive can organize outputs" to "output {} block can organize outputs using dynamic path closures".
    • Summary key pattern 6: Updated description and code snippet to show the output {} block instead of publishDir.

6 documentation files (zero publishDir references remain):
  - docs/en/docs/side_quests/essential_scripting_patterns.md - Removed publishDir from GENERATE_REPORT code block
  - docs/en/docs/side_quests/metadata.md - Removed publishDir from COWPY code block
  - docs/en/docs/side_quests/dev_environment.md - Removed publishDir from FASTQC code block, changed search example from
  publishDir to container
  - docs/en/docs/side_quests/debugging.md - Removed publishDir from all 3 processes in corrected workflow, added
  publish:/output {} blocks
  - docs/en/docs/side_quests/nf-test.md - Removed publishDir from both processes, added publish:/output {} blocks
  - docs/en/docs/side_quests/working_with_files.md - Rewrote section 6 to use output {} block pattern; updated process output
  to emit full meta; updated sections 6.1, 6.2.2, 6.4, Takeaway, and Summary

  ~25 script files (zero publishDir references remain):
  - workflows_of_workflows: 6 module files (removed publishDir), 1 main.nf (added publish/output)
  - essential_scripting_patterns: 2 module files (removed publishDir), 1 main.nf (added publish/output)
  - metadata: 3 module files (removed publishDir), 2 main.nf files (added publish/output)
  - ide_features: 5 script files (removed publishDir from all, added publish/output to both workflow files)
  - debugging: 2 workflow files (removed publishDir, added publish/output)
  - nf-test: 1 main.nf (removed publishDir, added publish/output)
  - working_with_files: 2 module files (removed publishDir, changed output to emit full meta), 1 main.nf (added publish/output
   with dynamic path closure)
@netlify
Copy link

netlify bot commented Feb 12, 2026

Deploy Preview for nextflow-training ready!

Name Link
🔨 Latest commit b2b4a12
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-training/deploys/69956c7435bffe00080cf768
😎 Deploy Preview https://deploy-preview-884--nextflow-training.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

Nextflow linting complete!

❌ 1 files had 1 errors
✅ 173 files had no errors
🔧 130 files would be changed by auto-formatting

💡 Tip: Click filename locations to go directly to that code.

View all 1 issues
Type Location Message
Error hello-nf-core/solutions/core-hello-part2/nextflow.config:154:17 Invalid include source: '/home/runner/work/training/training/hello-nf-core/solutions/core-hello-part2/conf/test_full.config'
View formatting changes
FileDiff
hello-nextflow/solutions/1-hello-world/hello-world-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     output:
     path 'output.txt'
 
hello-nextflow/solutions/1-hello-world/hello-world-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/2-hello-channels/hello-channels-1.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,7 +28,7 @@ workflow {
     main:
     // create a channel for inputs
     greeting_ch = channel.of('Hello Channels!')
-                        .view()
+        .view()
     // emit a greeting
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,7 +28,7 @@ workflow {
     main:
     // create a channel for inputs
     greeting_ch = channel.of('Hello', 'Bonjour', 'Holà')
-                        .view()
+        .view()
     // emit a greeting
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -28,12 +27,12 @@ workflow {
 
     main:
     // declare an array of input greetings
-    greetings_array = ['Hello','Bonjour','Holà']
+    greetings_array = ['Hello', 'Bonjour', 'Holà']
     // create a channel for inputs
... (truncated)
hello-nextflow/solutions/2-hello-channels/hello-channels-4.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -29,11 +28,11 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .view { csv -> "Before splitCsv: $csv" }
-                        .splitCsv()
-                        .view { csv -> "After splitCsv: $csv" }
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-1.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-2.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-3.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/3-hello-workflow/hello-workflow-4.nf
View
@@ -4,7 +4,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
@@ -21,7 +20,6 @@ process sayHello {
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-2.nf
View
@@ -7,7 +7,6 @@ include { sayHello } from './modules/sayHello.nf'
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
@@ -24,7 +23,6 @@ process convertToUpper {
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-3.nf
View
@@ -8,7 +8,6 @@ include { convertToUpper } from './modules/convertToUpper.nf'
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
@@ -38,8 +37,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
... (truncated)
hello-nextflow/solutions/4-hello-modules/hello-modules-4.nf
View
@@ -18,8 +18,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/4-hello-modules/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/4-hello-modules/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/4-hello-modules/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/5-hello-containers/hello-containers-2.nf
View
@@ -20,8 +20,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/5-hello-containers/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/5-hello-containers/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/5-hello-containers/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/6-hello-config/hello-config.nf
View
@@ -20,8 +20,8 @@ workflow {
     main:
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.input)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
     // emit a greeting
     sayHello(greeting_ch)
     // convert the greeting to uppercase
hello-nextflow/solutions/6-hello-config/modules/collectGreetings.nf
View
@@ -2,7 +2,6 @@
  * Collect uppercase greetings into a single output file
  */
 process collectGreetings {
-
     input:
     path input_files
     val batch_name
hello-nextflow/solutions/6-hello-config/modules/convertToUpper.nf
View
@@ -2,7 +2,6 @@
  * Use a text replacement tool to convert the greeting to uppercase
  */
 process convertToUpper {
-
     input:
     path input_file
 
hello-nextflow/solutions/6-hello-config/modules/sayHello.nf
View
@@ -2,7 +2,6 @@
  * Use echo to print 'Hello World!' to a file
  */
 process sayHello {
-
     input:
     val greeting
 
hello-nextflow/solutions/6-hello-config/nextflow.config
View
@@ -6,7 +6,7 @@ conda.enabled = true
 */
 process {
     memory = 1.GB
-    withName: 'cowpy' {
+    withName: cowpy {
         memory = 2.GB
         cpus = 2
     }
@@ -32,11 +32,7 @@ profiles {
     univ_hpc {
         process.executor = 'slurm'
         conda.enabled = true
-        process.resourceLimits = [
-            memory: 750.GB,
... (truncated)
hello-nf-core/solutions/composable-hello/hello.nf
View
@@ -14,9 +14,7 @@ include { collectGreetings } from './modules/collectGreetings.nf'
 include { cowpy } from './modules/cowpy.nf'
 
 workflow HELLO {
-
     take:
-    // channel of greetings
     greeting_ch
 
     main:
hello-nf-core/solutions/composable-hello/main.nf
View
@@ -9,12 +9,12 @@ params.greeting = 'greetings.csv'
 workflow {
     // create a channel for inputs from a CSV file
     greeting_ch = channel.fromPath(params.greeting)
-                        .splitCsv()
-                        .map { line -> line[0] }
+        .splitCsv()
+        .map { line -> line[0] }
 
     // call the imported workflow on the channel of greetings
     HELLO(greeting_ch)
 
     // view the outputs emitted by the workflow
-    HELLO.out.view { output -> "Output: $output" }
+    HELLO.out.view { output -> "Output: ${output}" }
... (truncated)
hello-nf-core/solutions/composable-hello/modules/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/composable-hello/modules/convertToUpper.nf
View
@@ -13,6 +13,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/composable-hello/modules/cowpy.nf
View
@@ -15,6 +15,6 @@ process cowpy {
 
     script:
     """
-    cat $input_file | cowpy -c "$character" > cowpy-${input_file}
+    cat ${input_file} | cowpy -c "${character}" > cowpy-${input_file}
     """
 }
hello-nf-core/solutions/composable-hello/modules/sayHello.nf
View
@@ -13,6 +13,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/conf/base.config
View
@@ -11,13 +11,13 @@
 process {
 
     // TODO nf-core: Check the defaults for all processes
-    cpus   = { 1      * task.attempt }
-    memory = { 6.GB   * task.attempt }
-    time   = { 4.h    * task.attempt }
+    cpus = { 1 * task.attempt }
+    memory = { 6.GB * task.attempt }
+    time = { 4.h * task.attempt }
 
     errorStrategy = { task.exitStatus in ((130..145) + 104 + 175) ? 'retry' : 'finish' }
-    maxRetries    = 1
-    maxErrors     = '-1'
+    maxRetries = 1
... (truncated)
hello-nf-core/solutions/core-hello-part2/conf/modules.config
View
@@ -12,10 +12,5 @@
 
 process {
 
-    publishDir = [
-        path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
-        mode: params.publish_dir_mode,
-        saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
-    ]
-
+    publishDir = [path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" }, mode: params.publish_dir_mode, saveAs: { filename -> filename.equals('versions.yml') ? null : filename }]
 }
hello-nf-core/solutions/core-hello-part2/conf/test.config
View
@@ -11,21 +11,17 @@
 */
 
 process {
-    resourceLimits = [
-        cpus: 2,
-        memory: '4.GB',
-        time: '1.h'
-    ]
+    resourceLimits = [cpus: 2, memory: '4.GB', time: '1.h']
 }
 
 params {
-    config_profile_name        = 'Test profile'
+    config_profile_name = 'Test profile'
... (truncated)
hello-nf-core/solutions/core-hello-part2/main.nf
View
@@ -13,9 +13,9 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-include { HELLO  } from './workflows/hello'
+include { HELLO } from './workflows/hello'
 include { PIPELINE_INITIALISATION } from './subworkflows/local/utils_nfcore_hello_pipeline'
-include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hello_pipeline'
+include { PIPELINE_COMPLETION } from './subworkflows/local/utils_nfcore_hello_pipeline'
 /*
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     NAMED WORKFLOWS FOR PIPELINE
@@ -26,7 +26,6 @@ include { PIPELINE_COMPLETION     } from './subworkflows/local/utils_nfcore_hell
 // WORKFLOW: Run main analysis pipeline depending on type of input
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/modules/local/collectGreetings.nf
View
@@ -10,8 +10,8 @@ process collectGreetings {
     val batch_name
 
     output:
-    path "COLLECTED-${batch_name}-output.txt" , emit: outfile
-    val count_greetings , emit: count
+    path "COLLECTED-${batch_name}-output.txt", emit: outfile
+    val count_greetings, emit: count
 
     script:
     count_greetings = input_files.size()
hello-nf-core/solutions/core-hello-part2/modules/local/convertToUpper.nf
View
@@ -13,6 +13,6 @@ process convertToUpper {
 
     script:
     """
-    cat '$input_file' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
+    cat '${input_file}' | tr '[a-z]' '[A-Z]' > 'UPPER-${input_file}'
     """
 }
hello-nf-core/solutions/core-hello-part2/modules/local/cowpy.nf
View
@@ -15,6 +15,6 @@ process cowpy {
 
     script:
     """
-    cat $input_file | cowpy -c "$character" > cowpy-${input_file}
+    cat ${input_file} | cowpy -c "${character}" > cowpy-${input_file}
     """
 }
hello-nf-core/solutions/core-hello-part2/modules/local/sayHello.nf
View
@@ -13,6 +13,6 @@ process sayHello {
 
     script:
     """
-    echo '$greeting' > '$greeting-output.txt'
+    echo '${greeting}' > '${greeting}-output.txt'
     """
 }
hello-nf-core/solutions/core-hello-part2/subworkflows/local/utils_nfcore_hello_pipeline/main.nf
View
@@ -8,13 +8,13 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-include { UTILS_NFSCHEMA_PLUGIN     } from '../../nf-core/utils_nfschema_plugin'
-include { paramsSummaryMap          } from 'plugin/nf-schema'
-include { samplesheetToList         } from 'plugin/nf-schema'
-include { paramsHelp                } from 'plugin/nf-schema'
-include { completionSummary         } from '../../nf-core/utils_nfcore_pipeline'
-include { UTILS_NFCORE_PIPELINE     } from '../../nf-core/utils_nfcore_pipeline'
-include { UTILS_NEXTFLOW_PIPELINE   } from '../../nf-core/utils_nextflow_pipeline'
+include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin'
+include { paramsSummaryMap } from 'plugin/nf-schema'
+include { samplesheetToList } from 'plugin/nf-schema'
+include { paramsHelp } from 'plugin/nf-schema'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/main.nf
View
@@ -10,9 +10,9 @@
 
 workflow UTILS_NEXTFLOW_PIPELINE {
     take:
-    print_version        // boolean: print version
-    dump_parameters      // boolean: dump parameters
-    outdir               //    path: base directory used to publish pipeline results
+    print_version // boolean: print version
+    dump_parameters // boolean: dump parameters
+    outdir //    path: base directory used to publish pipeline results
     check_conda_channels // boolean: check conda channels
 
     main:
@@ -72,10 +72,10 @@ def getWorkflowVersion() {
 //
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config
View
@@ -1,9 +1,9 @@
 manifest {
-    name            = 'nextflow_workflow'
-    author          = """nf-core"""
-    homePage        = 'https://127.0.0.1'
-    description     = """Dummy pipeline"""
+    name = 'nextflow_workflow'
+    author = """nf-core"""
+    homePage = 'https://127.0.0.1'
+    description = """Dummy pipeline"""
     nextflowVersion = '!>=23.04.0'
-    version         = '9.9.9'
-    doi             = 'https://doi.org/10.5281/zenodo.5070524'
+    version = '9.9.9'
+    doi = 'https://doi.org/10.5281/zenodo.5070524'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/main.nf
View
@@ -125,12 +125,12 @@ def paramsSummaryMultiqc(summary_params) {
         }
 
     def yaml_file_text = "id: '${workflow.manifest.name.replace('/', '-')}-summary'\n" as String
-    yaml_file_text     += "description: ' - this information is collected when the pipeline is started.'\n"
-    yaml_file_text     += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
-    yaml_file_text     += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
-    yaml_file_text     += "plot_type: 'html'\n"
-    yaml_file_text     += "data: |\n"
-    yaml_file_text     += "${summary_section}"
+    yaml_file_text += "description: ' - this information is collected when the pipeline is started.'\n"
+    yaml_file_text += "section_name: '${workflow.manifest.name} Workflow Summary'\n"
+    yaml_file_text += "section_href: 'https://github.com/${workflow.manifest.name}'\n"
+    yaml_file_text += "plot_type: 'html'\n"
+    yaml_file_text += "data: |\n"
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config
View
@@ -1,9 +1,9 @@
 manifest {
-    name            = 'nextflow_workflow'
-    author          = """nf-core"""
-    homePage        = 'https://127.0.0.1'
-    description     = """Dummy pipeline"""
-    nextflowVersion  = '!>=23.04.0'
-    version         = '9.9.9'
-    doi             = 'https://doi.org/10.5281/zenodo.5070524'
+    name = 'nextflow_workflow'
+    author = """nf-core"""
+    homePage = 'https://127.0.0.1'
+    description = """Dummy pipeline"""
+    nextflowVersion = '!>=23.04.0'
+    version = '9.9.9'
... (truncated)
hello-nf-core/solutions/core-hello-part2/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part2/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part3/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part3/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part3/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part3/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part3/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part3/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part4/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part4/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/cowpy/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part4/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part4/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part4/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part4/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-part5/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-part5/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-part5/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/convertToUpper.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/cowpy.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/cowpy/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/local/sayHello.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/tests/nextflow_unzipped_zipped.config(truncated)
hello-nf-core/solutions/core-hello-part5/modules/nf-core/cat/cat/tests/nextflow_zipped_unzipped.config(truncated)
hello-nf-core/solutions/core-hello-part5/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-part5/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-part5/workflows/hello.nf(truncated)
hello-nf-core/solutions/core-hello-start/conf/base.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/modules.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/test.config(truncated)
hello-nf-core/solutions/core-hello-start/conf/test_full.config(truncated)
hello-nf-core/solutions/core-hello-start/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/local/utils_nfcore_hello_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nextflow_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nextflow_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfcore_pipeline/tests/nextflow.config(truncated)
hello-nf-core/solutions/core-hello-start/subworkflows/nf-core/utils_nfschema_plugin/main.nf(truncated)
hello-nf-core/solutions/core-hello-start/workflows/hello.nf(truncated)
nextflow-run/solutions/3-main.nf(truncated)
nextflow-run/solutions/modules/collectGreetings.nf(truncated)
nextflow-run/solutions/modules/convertToUpper.nf(truncated)
nextflow-run/solutions/modules/sayHello.nf(truncated)
nextflow-run/solutions/nextflow.config(truncated)
side-quests/solutions/debugging/buggy_workflow.nf(truncated)
side-quests/solutions/essential_scripting_patterns/main.nf(truncated)
side-quests/solutions/essential_scripting_patterns/modules/generate_report.nf(truncated)
side-quests/solutions/metadata/3.2/main.nf(truncated)
side-quests/solutions/metadata/3.3/main.nf(truncated)
side-quests/solutions/workflows_of_workflows/main.nf(truncated)
side-quests/solutions/working_with_files/6/main.nf(truncated)

@vdauwera vdauwera self-assigned this Feb 12, 2026
@vdauwera vdauwera requested a review from bentsherman February 12, 2026 15:04
Comment on lines 2521 to 2522
directory params.output
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax is from an old preview version. These settings should go in the config:

outputDir = params.output
workflow.output.mode = 'copy'

Comment on lines 168 to 169
directory 'results'
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the outputs here need to be declared even if they don't require any custom settings:

output {
    greetings {
        // path '.'
    }

    upper_greetings {
        // path '.'
    }
}

I commented the path '.' because that's what it will do by default, but you could add it if you want to be explicit / not have empty output declarations

Comment on lines +1595 to +1596
The `tag` directive uses closure syntax (`{ ... }`) because it references input variables (`meta`) that aren't available until the process runs.
The closure defers evaluation until runtime.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly off-topic -- with the v2 parser you don't need the closure here anymore, it's optional. If this guide is assuming the v2 parser, then it should be safe to remove the closure

But you might still want to have a note about the fact that the closure used to be needed

files
]
}
.set { ch_samples }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly off-topic -- try to prefer assignments over set and tuple() over [] (when making a tuple):

        ch_samples = ch_files.map { id,  files ->
           def (sample, replicate, type, readNum) = id.tokenize('_')
           tuple(
               [
                   id: sample,
                   replicate: replicate.replace('rep', ''),
                   type: type
               ],
               files
           )
        }

This code will work better with the type checker in the future

Comment on lines 1720 to 1721
directory 'results'
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, move to config

Comment on lines 2079 to 2080
directory 'results'
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, move to config

Comment on lines 97 to 98
directory params.output
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, move to config

Comment on lines +91 to +93
processed = processFiles.out
heavy = heavyProcess.out
files = handleFiles.out
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly off-topic -- I think we should try to use regular assignments instead of .out as much as possible, since .out is a relatively unusual syntax pattern whereas assignments are a widely understood concept

I think .out is mainly useful for when a process / workflow has multiple outputs, but in this case, each process has only one output and you're already assigning the first two (processed_ch and heavy_ch), so I think it's reasonable to avoid .out entirely here.

Comment on lines +52 to +53
fastqc_html = FASTQC.out.html
fastqc_zip = FASTQC.out.zip
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(continuing discussion of .out vs assignments)

Here I think it's fair to use .out. Hopefully with records, this will collapse to a single channel of records, at which point we could remove the use of .out here as well.

Copy link
Member

@bentsherman bentsherman Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, what I would go ahead and do here is to join the two channels into a single channel:

    ch_fastqc = FASTQC.out.html.join(FASTQC.out.zip)

    publish:
    fastqc = ch_fastqc

Then you only have one output declaration:

output {
    fastqc {
        path 'fastqc'
    }
}

My intuition is that it will be better to combine related outputs into a single workflow output as much as possible

You could imagine taking this further and combining all "per-sample" outputs into a single workflow output called samples, while using the dynamic path closure to keep organizing output files by tool. That is more a matter of personal taste, but at the very least I think we should at least collapse to one workflow output per process output, as a best practice.

Copy link
Member

@bentsherman bentsherman Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also convert the tuples to maps, in anticipation of records:

    ch_fastqc = FASTQC.out.html.join(FASTQC.out.zip)

    publish:
    fastqc = ch_fastqc.map { sample_id, html, zip -> [sample_id: sample_id, html: html, zip: zip] }

But I wouldn't say this is necessary at this point

Comment on lines 57 to 58
directory params.output_dir
mode 'copy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, move to config

}
counts {
path 'counts'
}
Copy link
Member

@bentsherman bentsherman Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(continuing discussion of collapsing outputs)

Just to illustrate, this is what it would like to collapse outputs to the extreme:

    samples { s ->
        s.fastqc_html >> 'fastqc'
        s.fastqc_zip >> 'fastqc'
        s.trimmed_fastq >> 'trimmed'
        s.alignments >> 'alignments'
        s.counts >> 'counts'
    }

This assumes you join the individual output channels into a single channel of maps / records:

    samples = RNASEQ_PIPELINE.out.fastqc
        .join( RNASEQ_PIPELINE.out.trimmed )
        .join( RNASEQ_PIPELINE.out.alignments )
        .join( RNASEQ_PIPELINE.out.counts )
        .map { sample_id, fastqc_html, fastqc_zip, trimmed_fastq, alignments, counts -> [sample_id: sample_id, fastqc_html: fastqc_html, fastqc_zip: fastqc_zip, trimmed_fastq: trimmed_fastq, alignments: alignments, counts: counts] }

As you can see, it gets pretty ugly when you're still using tuples... so I'm not suggesting that we do this now. Just something to consider for when we eventually introduce records

@bentsherman
Copy link
Member

I think that concludes my review. Main two points are:

  1. directory and mode in the output block need to be moved to the config
  2. every output assigned in the publish: section needs to be declared in the output block

Aside from that, I left some extra thoughts about best practices. Feel free to take them or leave them

Hopefully you can just throw my general suggestions into a spec and let the AI update all of the code examples for you 😄

@vdauwera
Copy link
Collaborator Author

I think that concludes my review. Main two points are:

  1. directory and mode in the output block need to be moved to the config
  2. every output assigned in the publish: section needs to be declared in the output block

Aside from that, I left some extra thoughts about best practices. Feel free to take them or leave them

Hopefully you can just throw my general suggestions into a spec and let the AI update all of the code examples for you 😄

Thanks @bentsherman, this is super helpful!

Move directory/mode from output {} blocks to nextflow.config files,
declare all published outputs in output {} blocks, use variable
assignments instead of .out in publish blocks, and use tuple()/
assignment over []/​.set {} for type-checker compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

docker.enabled = true

outputDir = 'results'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth, the output dir defaults to results, so you could omit this setting. But I think it's totally fair if you want to be explicit about it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments