Skip to Content
NodebarR Nodes

R Nodes

R nodes let you use the entire Bioconductor and CRAN ecosystem inside your workflow. Here’s how they work.


The Simplest R Node

Here’s a complete, working R node:

library(DESeq2) COUNTS_MATRIX <- "data/counts.csv" SAMPLE_INFO <- "data/samples.csv" OUTPUT_DIR <- "results/" dir.create(OUTPUT_DIR, recursive = TRUE, showWarnings = FALSE) dds <- DESeqDataSetFromMatrix(countData = read.csv(COUNTS_MATRIX), colData = read.csv(SAMPLE_INFO), design = ~condition) dds <- DESeq(dds) res <- results(dds) write.csv(res, file.path(OUTPUT_DIR, "results.csv")) return(res)

This node has 3 inputs (COUNTS_MATRIX, SAMPLE_INFO, OUTPUT_DIR) and 1 output (res).


No Decorator Needed

Unlike Python, R nodes don’t need a decorator. You just write R code — the system figures out inputs and outputs automatically.


What Is an Input?

Inputs are UPPERCASE variable assignments at the top of your script.

COUNTS_MATRIX <- "data/counts.csv" SAMPLE_INFO <- "data/samples.csv" OUTPUT_DIR <- "results/"

This creates three inputs: COUNTS_MATRIX, SAMPLE_INFO, and OUTPUT_DIR. When the workflow runs, values from upstream nodes replace these defaults automatically.

Use Empty Strings for File Inputs

For file paths and string inputs, use empty quotes as the default:

COUNTS_MATRIX <- "" # gets replaced by upstream connection OUTPUT_DIR <- "" # gets replaced by upstream connection

For numeric inputs, provide a sensible default:

ALPHA <- 0.05 # used if nothing is connected

Why UPPERCASE?

The system only detects uppercase variables (like COUNTS_MATRIX, ALPHA) as inputs. Lowercase variables (like counts_matrix) are treated as intermediate work, not inputs.

This is the same convention as bash nodes — if you’ve used bash nodes, R inputs work the same way.


What Is an Output?

Outputs come from the return() statement.

res <- results(dds) return(res) # ↑ # output 1

Whatever you pass to return() becomes available to downstream nodes.

Passing Multiple Values Downstream

R nodes support one output. If you need to pass multiple things downstream, combine them into a single variable first:

combined <- list(results = res, normalized = norm_counts) return(combined)

The downstream node receives combined as a list. It can then access combined$results and combined$normalized.

No return()?

If you don’t use return(), the system uses the last non-input variable you assigned as the output. But explicit return() is always clearer.


How Variables Arrive

When you connect an upstream node to your R node, the variable appears in the R environment automatically. Just use it by name:

# COUNTS_MATRIX arrives from upstream — just use it dds <- DESeqDataSetFromMatrix(countData = read.csv(COUNTS_MATRIX), ...)

No input$COUNTS_MATRIX or input[['COUNTS_MATRIX']] — just COUNTS_MATRIX.


A Complete Example

Here’s a real DESeq2 differential expression node:

library(DESeq2) COUNTS_MATRIX <- "" SAMPLE_INFO <- "" DESIGN <- "~condition" OUTPUT_DIR <- "" REF_COL <- "condition" REF_LEVEL <- "control" ALPHA <- 0.05 dir.create(OUTPUT_DIR, recursive = TRUE, showWarnings = FALSE) counts <- read.csv(COUNTS_MATRIX, row.names = 1) samples <- read.csv(SAMPLE_INFO) dds <- DESeqDataSetFromMatrix(countData = counts, colData = samples, design = as.formula(DESIGN)) dds <- DESeq(dds) res <- results(dds, alpha = ALPHA) write.csv(res, file.path(OUTPUT_DIR, "deseq2_results.csv")) return(res)

Good to Know

Verbose output? Use sink()

R packages like DESeq2 and Seurat can be very chatty, printing progress for every step. Redirect verbose output to a file:

sink("deseq2.log") dds <- DESeq(dds) sink() # restore stdout print("DESeq2 complete. See deseq2.log for details.") res <- results(dds) return(res)

Libraries go at the top

Always put library() calls at the top of your script. They run inline as part of your code, so anything declared before them won’t have access to the library:

library(DESeq2) library(ggplot2) # Your code here...

Intermediate variables stay internal

When the R node finishes, only the variable in your return() is passed downstream. Your intermediate variables (dds, counts, samples) stay internal — they don’t clutter the workflow.

R runs in-process

R runs in-process via rpy2, sharing memory with the backend. For extremely large datasets, this may cause memory pressure. Consider splitting very large analyses into smaller steps.

No timeout

R nodes have no execution timeout. Long-running analyses are fine.


Quick Summary

ConceptHow it works
DecoratorNot needed — just write R code
InputsUPPERCASE variable assignments (VAR <- "value")
Empty defaultsUse "" for file/string inputs, numbers for numeric
Outputsreturn(variable)
No return?Last non-input variable becomes the output
Variable arrivalAutomatic — just use the variable name
Intermediate varsStay internal, not passed downstream
LibrariesUse library() at the top
Verbose outputUse sink() to redirect to a log file
In-processR runs in-process via rpy2 — watch memory for large data
No timeoutNodes can run for hours or days
Last updated on