--- title: Typed processes description: Use the typed process syntax in Nextflow to define statically typed inputs and outputs for processes. --- # Typed processes Typed processes use a new syntax for inputs and outputs that supports static typing. ```nextflow nextflow.enable.types = true process hello { input: message: String output: file('hello.txt') script: """ echo '${message}' > hello.txt """ } ``` For an overview of static typing and how to enable it, see [Static typing][static-typing-page]. For the complete syntax reference, see [Process (typed)][syntax-process-typed]. ## Inputs The `input:` section declares process inputs. In typed processes, each input declaration consists of a name and type: ```nextflow nextflow.enable.types = true process fastqc { input: meta: Map fastq: Path extra_args: String script: """ echo 'meta: ${meta}' echo 'fastq: ${fastq}' echo 'extra_args: ${extra_args}' """ } ``` All [standard types][stdlib-types] except for the dataflow types (`Channel` and `Value`) can be used as type annotations in processes. ### File inputs Nextflow automatically stages `Path` inputs and `Path` collections (such as `Set`) into the task directory. Path collections are rendered like any other collection when interpolated into a script (e.g. `[a.fastq, b.fastq]`). Use `join()` to render them as a space-separated list: ```nextflow nextflow.enable.types = true process cat { input: reads: List script: """ cat ${reads.join(' ')} """ } ``` ### Nullable inputs By default, tasks fail if any input receives a `null` value. To allow `null` values, add `?` to the type annotation: ```nextflow nextflow.enable.types = true process cat_opt { input: input: Path? stage: stageAs input, 'input.txt' output: stdout() script: ''' [[ -f input.txt ]] && cat input.txt || echo 'empty input' ''' } ``` ### Record inputs Record inputs can be declared using a record type: ```nextflow nextflow.enable.types = true process fastqc { input: sample: Sample script: """ echo 'id: ${sample.id}' echo 'fastq: ${sample.fastq}' """ } record Sample { id: String fastq: Path } ``` In this example, the record input is staged as `sample`, and `sample.fastq` is staged as an input file since it is declared with type `Path` in the `Sample` record type. Each field in the record type is staged into the task the same way as an individual input. When the process is invoked, the incoming record should contain the specified fields, or else the run will fail. If the incoming record has additional fields not declared by the process input, they are ignored. Record collections (such as `List`) are staged the same way. Each `Path` field is staged as an input file for every record in the collection, and `null` values of nullable fields are skipped: ```nextflow nextflow.enable.types = true process cat_samples { input: samples: List script: """ cat ${samples*.fastq.join(' ')} """ } ``` Record inputs can also be declared as a *destructured* input: ```nextflow nextflow.enable.types = true process fastqc { input: record( id: String, fastq: Path ) script: """ echo 'id: ${id}' echo 'fastq: ${fastq}' """ } ``` This pattern mirrors the standard `record()` function used to construct records. In this example, `fastq` is staged as an input file since the `fastq` field is declared with type `Path`. :::tip Record inputs are a useful way to select a subset of fields from a larger record. This way, the process stages only what it needs, keeping related data together in your workflow logic. ::: Only the `Path` fields declared by the process input are staged. To avoid staging files that a process doesn't need, omit those fields from the input declaration. If the process needs the metadata of a record but none of its files, declare the input with the generic `Record` type: ```nextflow nextflow.enable.types = true process report { input: samples: List script: """ echo 'ids: ${samples*.id.join(' ')}' """ } ``` In this example, the fields of each record can be accessed in the task, but no files are staged. Any `Path` fields still refer to the original file locations, so they shouldn't be used by the task script. ### Tuple inputs Tuple inputs can be declared as a *destructured* input: ```nextflow nextflow.enable.types = true process fastqc { input: tuple(id: String, fastq: Path) script: """ echo 'id: ${id}' echo 'fastq: ${fastq}' """ } ``` This pattern mirrors the standard `tuple()` function used to construct tuples. Each tuple component is staged into the task the same way as an individual input. ## Stage directives The `stage:` section defines custom staging behavior using *stage directives*. It should be specified after the `input:` section. These directives serve the same purpose as input qualifiers such as `env` and `stdin` in the legacy syntax. ### Environment variables The `env` directive declares an environment variable in terms of task inputs: ```nextflow nextflow.enable.types = true process echo_env { input: hello: String stage: env 'HELLO', hello script: ''' echo "$HELLO world!" ''' } ``` ### Standard input (stdin) The `stdin` directive defines the standard input of the task script: ```nextflow nextflow.enable.types = true process cat { input: message: String stage: stdin message script: """ cat - """ } ``` ### Custom file staging The `stageAs` directive stages an input file (or files) under a custom file pattern: ```nextflow nextflow.enable.types = true process blast { input: fasta: Path stage: stageAs fasta, 'query.fa' script: """ blastp -query query.fa -db nr """ } ``` The file pattern can also reference task inputs: ```nextflow nextflow.enable.types = true process grep { input: id: String fasta: Path stage: stageAs fasta, "${id}.fa" script: """ cat ${id}.fa | grep '>' """ } ``` Input files are staged under their original names by default, so two input files with the same name (e.g. from different records in a record collection) cause the task to fail with a file name collision error. Use a file pattern to stage each file in its own directory: ```nextflow nextflow.enable.types = true process cat_samples { input: samples: List stage: stageAs samples*.fastq, 'fastq?/*' script: """ cat ${samples*.fastq.join(' ')} """ } ``` In this example, the files are staged as `fastq1/`, `fastq2/`, and so on. :::note The `stageAs` directive doesn't accept `null` values. To stage a nullable field, remove the `null` values first, e.g. `stageAs samples*.idx.findAll { idx -> idx != null }, 'idx?/*'`. Wildcards are numbered separately for each `stageAs` directive, after the `null` values are removed, so the files of a record might not have the same number in each directive. ::: For more information about the available stage directives, see [Inputs and outputs (typed)][process-reference-typed]. ## Outputs The `output:` section declares the outputs of a typed process. Each output declaration consists of a name, an optional type, and an output value: ```nextflow nextflow.enable.types = true process echo { input: message: String output: out_env: String = env('MESSAGE') out_file: Path = file('message.txt') out_std: String = stdout() script: """ export MESSAGE='${message}' echo \$MESSAGE > message.txt cat message.txt """ } ``` When there is only one output, the name can be omitted: ```nextflow nextflow.enable.types = true process echo { input: message: String output: stdout() script: """ echo '${message}' """ } ``` For more information about the available output functions, see [Inputs and outputs (typed)][process-reference-typed]. ### File outputs You can use the `file()` and `files()` functions in the `output:` section to get a single file or collection of files from the task directory. By default, the `file()` function fails if the specified file is not present in the task directory. You can specify `optional: true` to allow missing files. The `file()` function returns `null` for missing files. For example: ```nextflow nextflow.enable.types = true process foo { output: file('output.txt', optional: true) script: """ exit 0 """ } ``` Similarly, the `files()` function fails if no files match the given pattern. You can specify `optional: true` to return an empty set instead. ### Structured outputs Whereas legacy process outputs could only be structured using specific qualifiers like `val` and `tuple`, typed process outputs are plain values. The `record()` standard library function can be used to create a record: ```nextflow nextflow.enable.types = true process fastqc { input: record( id: String, fastq: Path ) output: record( id: id, fastqc: file('fastqc_logs') ) script: // ... } ``` The `tuple()` standard library function can be used to create a tuple: ```nextflow nextflow.enable.types = true process fastqc { input: tuple(id: String, fastq: Path) output: tuple(id, file('fastqc_logs')) script: // ... } ``` {/* (process-typed-topics) */} ## Topics The `topic:` section emits values to [topic channels][channel-topic]. A topic emission consists of an output value and a topic name: ```nextflow nextflow.enable.types = true process cat { input: message: Path output: stdout() topic: tuple('bash', eval('bash --version')) >> 'versions' tuple('cat', eval('cat --version')) >> 'versions' script: """ cat ${message} """ } ``` Topic emissions can use the same [output functions][process-reference-typed] as the `output:` section. See [Collecting values with topic channels][tutorial-topic-channels] for a practical example. ## Script The `script:` and `exec:` sections behave the same way as [legacy processes][process-script]. ## Stub The `stub:` section behaves the same way as [legacy processes][process-stub]. ## Directives Directives behave the same way as [legacy processes][process-directives]. [channel-topic]: ./reference/stdlib-namespaces/channel#topic [process-reference-typed]: ./reference/syntax#process-typed [process-directives]: ./process#directives [process-script]: ./process#script [process-stub]: ./process#stub [static-typing-page]: ./static-typing [stdlib-types]: ./reference/stdlib-types [syntax-process-typed]: ./reference/syntax#process-typed [tutorial-topic-channels]: ./tutorials/topic-channels