(migrating-26-04-page)=

# Migrating to 26.04

[Nextflow 26.04](https://github.com/nextflow-io/nextflow/releases/tag/v26.04.0) was released on April 29, 2026.

## New features

<h3>Module system</h3>

Nextflow now has native support for publishing, installing, running, and including remote modules using the [Nextflow registry](https://registry.nextflow.io/).

The new `module` command can be used to work with remote modules:

```bash
# Run a module directly
nextflow module run nf-core/fastqc --meta.id 1 --reads sample1.fastq

# Search for modules in registry
nextflow module search bwa

# View info about a module
nextflow module view nf-core/bwa/mem

# Install a module
nextflow module install nf-core/bwa/mem
```

Remote modules are installed into the `modules` directory of your project. They can be included in scripts by name instead of a relative path:

```nextflow
// before
include { BWA_MEM } from '../../../modules/nf-core/bwa/mem'

// after
include { BWA_MEM } from 'nf-core/bwa/mem'
```

:::{note}
All [nf-core modules](https://github.com/nf-core/modules) are automatically synced to the registry from GitHub. They are available as `nf-core/<name>` as shown above.
:::

See the {ref}`Modules overview <modules-page>` and {ref}`cli-module` command reference for details.

<h3>Record types</h3>

Records are a new data structure for modeling composite data. They serve as an alternative to tuples. While tuple elements are accessed by index, record fields are accessed by name. This allows you to model data with meaningful names rather than keeping track of the order of tuple elements.

A record can be created using the `record()` function:

```nextflow
sample = record(
    id: '1',
    fastq_1: file('1_1.fastq'),
    fastq_2: file('1_2.fastq')
)

println sample.id
println sample.foo  // error: unrecognized property `foo`
```

Record types are a way to define custom types for validating records:

```nextflow
record Sample {
    id: String
    fastq_1: Path
    fastq_2: Path?
}
```

While records created with the `record()` function can have any set of fields, record types can be used to specify a minimum set of requirements in a particular context, such as a process, function, or workflow:

```nextflow
def hello(sample: Sample) {
    println "Hello sample ${sample.id}!"
}

workflow {
    sample1 = record(id: '1', fastq_2: file('1_2.fastq'))
    hello(sample1) // error: `sample1` is missing `fastq_1` field required by Sample

    sample2 = record(id: '1', fastq_1: file('1_1.fastq'))
    hello(sample2) // ok

    sample3 = record(id: '1', single_end: true, fastq_1: file('1_1.fastq'))
    hello(sample3) // also ok
}
```

See {ref}`script-records` for details. See {ref}`migrating-static-types` for more information about migrating from tuples to records.

<h3>Static typing (preview)</h3>

:::{note}
Typed processes and typed workflows require the `nextflow.enable.types` feature flag to be enabled in every script that uses them.
:::

Nextflow 26.04 brings full support for static typing with {ref}`typed processes <process-typed-page>` and {ref}`typed workflows <workflow-typed-page>`.

Typed processes can now declare record inputs and outputs:

```nextflow
nextflow.enable.types = true

process FASTQC {
    input:
    record(
        id: String,
        fastq_1: Path,
        fastq_2: Path
    )

    output:
    record(
        id: id,
        fastqc: file('fastqc_logs')
    )

    script:
    // ...
}
```

Typed workflows can declare typed inputs and outputs, and provide first-class support for static typing in dataflow logic:

```nextflow
nextflow.enable.types = true

workflow RNASEQ {
    take:
    read_pairs_ch: Channel<Sample>
    transcriptome: Path

    main:
    index = INDEX(transcriptome)
    fastqc_ch = FASTQC(read_pairs_ch)
    quant_ch = QUANT(read_pairs_ch, index)
    samples_ch = fastqc_ch.join(quant_ch, by: 'id')

    emit:
    samples: Channel<AlignedSample> = samples_ch
}

record Sample { /* ... */ }
record AlignedSample { /* ... */ }
```

Several operators have been extended to support static typing and records:

- `combine` can now combine records or tuples
- `groupBy` is a statically-typed alternative to `groupTuple`
- `join` can now join records by matching field

Breaking changes from the {ref}`first preview <static-typing-first-preview>`:

- The `nextflow.preview.types` feature flag has been replaced with `nextflow.enable.types`.

- The `nextflow.enable.types` feature flag must be enabled in order to use type annotations in workflow takes/emits.

- The syntax for process tuple inputs has been updated:

    ```nextflow
    // 25.10
    input:
    (id, fastq_1, fastq_2): Tuple<String,Path,Path>

    // 26.04
    input:
    tuple(id: String, fastq_1: Path, fastq_2: Path)
    ```

- The method signature for the `stageAs` directive was changed from `(filePattern, value)` to `(value, filePattern)`.

See {ref}`migrating-static-types` for more information about migrating to static typing. See {ref}`migrating-static-types-operators` for best practices on using operators with static typing.

<h3>Process <code>hints</code> directive</h3>

The `hints` process directive allows you to specify executor-specific hints for individual processes.

For example, the AWS Batch executor uses the `consumableReources` hint for [resource-aware scheduling](https://aws.amazon.com/about-aws/whats-new/2025/02/aws-batch-resource-aware-scheduling/):

```nextflow
process hello {
    hints 'awsbatch/consumableResources': ['my-license': 1]

    // ...
}
```

Custom executors can use hints to control scheduling behavior in a fine-grained manner over configuration options.

See {ref}`process-hints` for details.

## Enhancements

<h3>Strict syntax parser enabled by default</h3>

The {ref}`strict syntax parser <strict-syntax-page>` is now enabled by default. This change adds the rich error checking from `nextflow lint` to `nextflow run`, and makes it easier to adopt new language features.

The legacy parser can be re-enabled by setting the `NXF_SYNTAX_PARSER` environment variable to `v1`.

<h3>Agent logging mode</h3>

Nextflow prints logs in an agent-friendly format when enabled via `NXF_AGENT_MODE=1`:

```console
$ NXF_AGENT_MODE=1 nextflow run [...]
[PIPELINE] nf-core/rnaseq 3.14.0 | profile=test,docker
[WORKDIR] /path/to/work
[PROCESS b8/623fc3] sayHello (3)
[PROCESS 5f/761e51] sayHello (2)

[WARN] Task runtime metrics are not reported when using macOS

[ERROR] FASTQC (sample_1)
exit: 127
cmd: fastqc --version
stderr: bash: fastqc: command not found
workdir: /path/to/work/ab/123456

[SUCCESS] completed=10 failed=0 cached=5
```

Agent mode provides minimal structured logging for efficient token usage. It is ideal when using agents to run and debug Nextflow runs.

<h3>Multi-revision checkout for pipelines</h3>

Nextflow now checks out pipelines separately by revision when running remote pipelines, allowing you to run multiple revisions of a pipeline at the same time.

Nextflow uses the default branch specified by the Git repository when no revision is specified, rather than defaulting to `master`. Since each revision is checked out separately, using a specific revision doesn't prevent the default branch from being used on subsequent runs.

The `manifest.defaultBranch` config option is no longer needed because of this update.

See {ref}`workflow-typed-params` for details. See {ref}`migrating-static-types` for a migration example.

<h3>Print workflow outputs on run completion</h3>

When the `output` block is defined, Nextflow prints a summary of the workflow outputs at the end of a run.

For example, given the following output block:

```nextflow
workflow {
    // ...
}

output {
    samples {
        path { sample -> "${sample.id}" }
        index {
            path 'samples.csv'
        }
    }

    multiqc_report {
        path 'multiqc_report.html'
    }
}
```

Nextflow prints the following summary:

```console
$ nextflow -q run main.nf
Outputs:

  /path/to/results

  samples: samples.csv

  multiqc_report: multiqc_report.html
```

You can specify `-output-format json` to produce JSON output instead:

```console
$ nextflow -q run main.nf -output-format json
{
    "samples": "/path/to/results/samples.csv",
    "multiqc_report": "/path/to/results/multiqc_report.html"
}
```

The `module run` command prints a summary of the module outputs:

```console
$ nextflow -q module run nf-core/fastqc --meta.id 1 --reads sample1.fastq -output-format json
{
    "html": [
        {
            "id": "SRR6357070_1"
        },
        "/path/to/results/SRR6357070_1_fastqc.html"
    ],
    "zip": [
        {
            "id": "SRR6357070_1"
        },
        "/path/to/results/SRR6357070_1_fastqc.zip"
    ]
}
```

See the {ref}`cli-run` command reference for details.

<h3>New <code>-project-dir</code> option for <code>lint</code> command</h3>

The `lint` command now has a `-project-dir` option, which can be used to specify the project root when linting files.

For example, given the following project structure:

```
├── lib
│   └── Utils.groovy
├── modules
│   └── nf-core
│       └── fastqc
│           ├── main.nf
│           └── ...
├── workflows
│   └── rnaseq.nf
├── main.nf
└── nextflow.config
```

You can specify `-project-dir` when linting from a location other than the project root:

```bash
cd workflows
nextflow lint -project-dir ../ rnaseq.nf
```

This option allows the linter to resolve remote module includes and Groovy code in the `lib` directory:

```nextflow
// workflows/rnaseq.nf

include { FASTQC } from 'nf-core/fastqc'

workflow RNASEQ {
    // ...

    Utils.validateInput( /* ... */ )

    // ...
}
```

See the {ref}`cli-lint` command reference for details.

<h3>Apple container support</h3>

Nextflow can run containers on macOS using [Apple container](https://github.com/apple/container), a lightweight container runtime for Apple silicon machines:

```groovy
process.container = 'nextflow/examples:latest'
appleContainer.enabled = true
```

See {ref}`container-apple` for details.

<h3>Seqera filesystem for datasets</h3>

Nextflow can download [Seqera Platform datasets](https://docs.seqera.io/platform-cloud/data/datasets) using the `seqera` URI scheme.

Seqera dataset URIs are specified as `seqera://<organization>/<workspace>/datasets/<name>[@version]`. For example:

```nextflow
params.dataset = 'seqera://seqeralabs/showcase/datasets/sarek_samples'

workflow {
    println file(params.dataset).text
}
```

A Platform access token with appropriate permissions is required to download non-public datasets. It can be specified using the `TOWER_ACCESS_TOKEN` environment variable or the `tower.accessToken` config option.

## Breaking changes

- The {ref}`strict syntax parser <strict-syntax-page>` is now enabled by default. The legacy parser can be enabled by setting the `NXF_SYNTAX_PARSER` environment variable to `v1`.

## Deprecations

- The `nextflow.enable.strict` feature flag is deprecated. It is not needed when {ref}`strict syntax <strict-syntax-page>` is enabled.

- The `manifest.defaultBranch` config option is deprecated. Nextflow can automatically detect the default branch when using a remote pipeline.

- The Path `listFiles()` method is deprecated. Use `listDirectory()` instead.

- Several operators have been deprecated. See {ref}`operator-page` for details.

## Miscellaneous

- New config option: `aws.batch.forceGlacierTransfer`
- New config option: `executor.onlyJobState`
- New config option: `google.batch.installOpsAgent`
- New config option: `google.batch.logsPath`
- New config option: `wave.build.conda.baseImage`
- New config option: `wave.build.template`
- New standard library function: `listDirectory()`
- Support Java 26
