Nextflow Static Typing
Static Typing in Nextflow
Nextflow 26.04 introduced support for static typing. This guide explains what static typing means in the context of Nextflow, why it was added to the language, and what you need to do to use it.
Background: How Nextflow Has Evolved
Nextflow has gone through several significant changes since it was first released. Understanding this progression helps explain why static typing looks the way it does.
DSL1 and DSL2
The original Nextflow language (sometimes called DSL1) embedded pipeline logic
directly inside process definitions. DSL2, introduced as the standard in
Nextflow 22.x, separated processes into standalone modules that could be
imported and reused. This is the include { PROCESS } from './modules/...'
pattern you have already seen.
DSL2 was a major improvement for code organization, but it left much of the channel wiring logic loosely defined. Channels carried values of any type, and it was easy to pass a tuple in the wrong order or call a deprecated operator without any warning.
The Strict Syntax
Nextflow 26.04 enables a stricter variant of the DSL2 syntax by default. The strict syntax removes several patterns that were previously allowed but known to cause problems:
- Using
Channel(uppercase) to access channel factories - Using the implicit
itclosure parameter - Using
setortapto assign channels - Composing logic with
|and& - Accessing process outputs via
.out
These are not arbitrary restrictions. Each of these patterns makes it difficult or impossible for Nextflow to understand the types of values flowing through your pipeline, which is required for type checking to work.
If you have code written in an older style, the nextflow lint command will
flag these patterns before you try to run anything.
Static Typing
Static typing builds on the strict syntax by allowing you to annotate your
code with type information. Instead of a channel that carries “something”,
you can declare a channel that carries Channel<Sample> — a channel of Sample
records with specific named fields.
When type annotations are present, the Nextflow language server can validate
them during development. It can tell you, before you run a single task, that a
channel of Sample records is compatible with a process expecting id: String
and fastq_1: Path. This is the same kind of feedback that a linter or
compiler gives you in other typed languages.
Enabling Static Typing
Static typing requires two things.
First, the strict syntax parser must be active. In Nextflow 26.04 it is enabled by default. If you are on an earlier version, you can activate it explicitly:
export NXF_SYNTAX_PARSER=v2
You only need to set this once per shell session. A good place to put it is in
your .bashrc or the activation script for your Nextflow conda environment.
Second, each script that uses typed processes or typed workflows must declare the preview feature flag at the top of the file:
nextflow.preview.types = true
This flag goes in the script itself, not in the config file, and it must be
present in every .nf file that uses typed syntax — including module files,
not just main.nf.
N.B. The params {} block and the output {} block work without this flag.
You only need nextflow.preview.types = true in files that contain typed
process inputs, typed process outputs, or typed workflow take:/emit:
declarations.
What Type Checking Does
The type checker runs inside the Nextflow language server, which is the backend used by the VS Code Nextflow extension. As you edit your pipeline, the language server continuously checks the types of channels as they flow between processes and operators.
For example, if you define a process that expects a Path input but you pass
it a String, the language server will underline the mismatch in the editor
and show you the error before you run anything.
This is useful for catching several common mistakes:
- Passing a channel of the wrong record type to a process
- Forgetting to include a required field in a record
- Using an operator that is not statically typed (and therefore breaks the type checker’s ability to validate downstream code)
The type checker does not run as part of nextflow lint or as part of a normal
nextflow run. It is a development-time tool. Running the pipeline will not
fail on type errors alone — but having the language server flag them while you
are writing code means you fix problems earlier and more cheaply.
Why Some Operators Are Not Statically Typed
Not every Nextflow operator can be given a precise return type. Operators like
splitCsv, groupTuple, and branch can return different types depending on
their arguments, and the type checker cannot always determine which type applies.
When you use one of these operators, the type checker treats the resulting
channel as having an unknown type, which means it cannot validate anything
downstream of that operator. The core operators — map, filter, flatMap,
join, collect, and others — all have precise types and are fully supported.
This is the primary reason why patterns like Channel.fromFilePairs followed
by splitCsv are replaced in typed pipelines. Those patterns produce channels
with unknown types. The replacement — a typed List<Sample> parameter loaded
from a CSV samplesheet — gives the channel a precise type that the checker can
follow through every downstream operator and process.
See Using operators with static typing and the Operators (typed) reference for more detail on which operators are fully supported.
Static Typing Is Optional
Existing pipelines do not need to be migrated. All DSL2 syntax continues to
work. You can also adopt static typing progressively: you might add a typed
params {} block first, then migrate individual processes, then migrate
workflows, without needing to change everything at once.
The one constraint is that you should not mix typed and legacy syntax within
the same workflow. If a workflow is declared as typed — using annotated take:
and emit: — then all of the patterns restricted by the strict syntax must be
absent from that workflow.
Summary
| Feature | Available since | Requires flag |
|---|---|---|
Typed params {} block |
25.10 | No |
Typed output {} block |
25.10 | No |
| Typed process inputs/outputs | 26.04 | nextflow.preview.types = true |
Typed workflow take:/emit: |
26.04 | nextflow.preview.types = true |
| Strict syntax parser | 26.04 (default) | NXF_SYNTAX_PARSER=v2 on older versions |