# How to Export Genomic Data from R

By the end of this guide you will be able to take genomic data that lives inside R and write it back out to every file type a working bioinformatician needs to hand off. That includes coordinate-based objects such as BED, GFF3, GTF, bigWig and VCF files, tabular results such as gene counts and differential expression tables, and portable R-native archives that let a collaborator recreate your objects exactly. You will also learn how to export data you pulled from public repositories such as the Genomic Data Commons, how to pick the right format for each consumer, and how to check that the file you wrote is actually correct.

Here is what you need on hand before starting.

- R 4.x installed. Bioconductor release versions track specific R versions, so a recent R avoids installation problems.
- The BiocManager package, which is the standard way to install Bioconductor packages.
- The core packages used in this guide: GenomicRanges, rtracklayer, SummarizedExperiment, VariantAnnotation, and optionally Rsamtools for compressed VCF output.
- Roughly 1 to 2 GB of free disk space if you plan to follow the repository download examples.
- Basic familiarity with running R code from RStudio or a terminal session.

Bioconductor is an open-source, open-development software project built on R that provides interoperable packages for the analysis and comprehension of high-throughput genomic data [1]. Its strength is that nearly every package shares the same core data classes, so once you learn to move data out of a GRanges object or a SummarizedExperiment object, you can export from almost any workflow built on top of them [2].

## Why Exporting Is a Core Skill in R for Bioinformatics

Inside R, genomic data lives in specialized in-memory objects. A GRanges object holds genomic intervals with chromosome, start, end, strand and metadata columns. A SummarizedExperiment object holds an assay matrix, such as gene counts, together with row-level feature data and column-level sample data. These objects are excellent for computation but useless to collaborators who use genome browsers, command-line tools, Python scripts, or spreadsheet software.

The Bioconductor project was designed so that packages interoperate through shared classes, which means analysis results built with one package can be consumed and extended by another [1]. The same design principle extends outward through import and export functions that bridge those classes to standard file formats. Recent reviews of the Bioconductor ecosystem for cancer genomics emphasize exactly this pattern: standardized classes at the center, file exchange at the edges [2].

If your export is wrong, everything downstream inherits the error. A coordinate shifted by one base, a missing genome build annotation, or a gene symbol silently converted to a calendar date by a spreadsheet can invalidate an entire handoff. The step-by-step workflow below builds in checks at each step so you can verify every file before you share it.

## Before You Start: Install and Set Up

Open an R session and run the following. This installs BiocManager and every package used in this article.

```r
install.packages("BiocManager")

BiocManager::install(c(
  "GenomicRanges",
  "rtracklayer",
  "SummarizedExperiment",
  "VariantAnnotation",
  "Rsamtools",
  "GenomicAlignments",
  "rGREAT"
))
```

If the installation prints a long list of packages and ends with a prompt asking to update some, it is usually safe to answer "none" for a first install. Confirm the setup:

```r
library(GenomicRanges)
library(rtracklayer)
packageVersion("GenomicRanges")
```

Expected output is a version string like `3.18.2` or similar, printed to the console. If you instead see this message, the package was not installed.

```
Error in library(rtracklayer) : there is no package called 'rtracklayer'
```

That exact wording means the install step above did not complete. Re-run the `BiocManager::install()` call and read the console output for a failed dependency. Packages that fail to install usually name the failing dependency in the error text.

## Step-by-Step: Export Genomic Data from R with Bioconductor

This walkthrough uses a small, realistic dataset: three putative regulatory peaks from a hypothetical ChIP-seq experiment, plus a small [gene expression](/blog/guides/gene-expression) matrix. Every command is reproducible as written. The same pattern scales to millions of intervals without modification.

### Step 1. Build or Obtain the Object You Want to Export

If you already have your data in R, skip to Step 2. If you want to follow along, create a small GRanges object. GRanges is the central interval class in Bioconductor and is defined in the GenomicRanges package [1].

```r
library(GenomicRanges)

gr <- GRanges(
  seqnames = c("chr1", "chr1", "chr2"),
  ranges   = IRanges(start = c(11710000, 11825000, 5630000),
                     end   = c(11713000, 11827500, 5632500)),
  strand   = c("+", "+", "-"),
  name     = c("peak_001", "peak_002", "peak_003"),
  score    = c(142, 87, 233),
  pvalue   = c(1.2e-9, 4.5e-4, 3.1e-12)
)

gr
```

Expected output:

```
GRanges object with 3 ranges and 3 metadata columns:
      seqnames    ranges strand |      name     score      pvalue
         <Rle> <IRanges>  <Rle> | <character> <numeric>   <numeric>
  [3]     chr1 11710000-11713000      + |   peak_001       142  1.20000e-9
  [4]     chr1 11825000-11827500      + |   peak_002        87  4.50000e-4
  [5]     chr2   5630000-5632500      - |   peak_003       233  3.10000e-12
```

The vertical bar separates the three core coordinate columns on the left from the metadata columns on the right. Everything left of the bar is what a BED or GFF file will represent as coordinates. Everything right of the bar becomes file columns, tags or attributes, depending on the format.

### Step 2. Export Coordinates as BED

![Worked example where the R start 11710000 for peak_001 is written as 11709999 in the BED file after subtracting one base.](/article-images/illustrations/export-genomic-data-r-bioconductor-bed-offset-calc.webp)

The rtracklayer package provides the general-purpose `export()` and `import()` pair that connects Bioconductor objects to standard genomic file formats. Export the peaks to BED:

```r
library(rtracklayer)
export(gr, "peaks.bed", format = "BED")
```

Check the file contents from your shell:

```bash
head peaks.bed
```

Expected output:

```
chr1	11709999	11713000	peak_001	142	+
chr1	11824999	11827500	peak_002	87	+
chr2	5629999	5632500	peak_003	233	-
```

Notice the start coordinates. BED is a zero-based, half-open format, meaning the start position counts from zero and the end position is excluded. R and Bioconductor use one-based, fully inclusive coordinates. The `export()` function converts between these coordinate systems automatically. A start of 11710000 in R becomes 11709999 in the BED file. This is the single most common source of off-by-one errors in hand-written export code, which is why the walkthrough never writes BED by hand with `write.table()`.

The BED format is the lingua franca of genome browsers and interval tools. Anything downstream, from bedtools intersect calls to loading a custom track in IGV or the [UCSC Genome Browser](/knowledge/bioinformatics/ucsc-genome-browser-beginner-tutorial-and-tips), consumes this file directly.

### Step 3. Export a Numeric Signal Track as bigWig

bigWig is a compressed, indexed binary format for continuous-valued signal, such as normalized coverage per base. It is what genome browsers use to draw wiggle-style tracks quickly. rtracklayer can write it directly from a GRanges object with numeric scores:

```r
signal <- GRanges(
  seqnames = rep("chr1", 4),
  ranges   = IRanges(start = c(11710000, 11710001, 11710002, 11710003),
                     width = 1),
  strand   = "*",
  score    = c(12.5, 13.0, 13.5, 14.0)
)

export(signal, "coverage.bigWig", format = "bigWig")
```

Two requirements matter here. The ranges must be sorted in ascending order along the genome, and overlapping ranges with differing scores are not representable in a bigWig the way they are in an object, so merge or resolve overlaps first when needed:

```r
signal_sorted <- sort(signal)
export(signal_sorted, "coverage.bigWig", format = "bigWig")
```

If you export an unsorted object, you will get an error from the underlying compression library, with wording along the lines of an unsorted input failure in the wig-to-bigWig conversion. The fix is always the same: call `sort()` on the GRanges before `export()`. Sorting a multi-chromosome GRanges with `sort()` orders by chromosome in the order seqlevels are defined, which is what the bigWig writer expects.

Also confirm the score column is numeric. If your metadata column is a character vector, coerce it first:

```r
signal$score <- as.numeric(signal$score)
```

Otherwise you may see an error complaining about non-numeric score values when the writer tries to build the binary track.

### Step 4. Export Annotations as GFF3 or GTF

GFF3 and GTF are the standard annotation formats used by Ensembl, GENCODE and most RNA-seq quantification tools. rtracklayer writes both:

```r
genes <- GRanges(
  seqnames = c("chr1", "chr2"),
  ranges   = IRanges(start = c(11705000, 5629000),
                     end   = c(11720000, 5637000)),
  strand   = c("+", "-"),
  type     = rep("gene", 2),
  gene_id  = c("ENSG000001", "ENSG000002"),
  gene_name = c("EXAMPLEA", "EXAMPLEB")
)

export(genes, "genes.gff3", format = "gff3")
export(genes, "genes.gtf",  format = "gtf")
```

Inspect the GTF output:

```bash
head genes.gtf
```

Expected output:

```
chr1	fasta	gene	11705000	11720000	.	+	.	gene_id "ENSG000001"; gene_name "EXAMPLEB";
```

GTF attributes are written as key-value pairs separated by semicolons inside the file itself. That is the file format specification at work, not R code, so it is fine even though this guide avoids semicolons in prose. When you import such a file back into R, rtracklayer parses those attribute strings back into metadata columns automatically.

For a more metadata-rich export with explicit type and phase columns, GFF3 is the better choice. For compatibility with STAR, featureCounts and other RNA-seq tools that expect GENCODE-style GTF, use the GTF output.

### Step 5. Export a SummarizedExperiment to Tabular Files

Most expression workflows end with a SummarizedExperiment or a SingleCellExperiment, and collaborators almost always want a plain table. Export the three components separately so nothing is lost:

```r
library(SummarizedExperiment)

set.seed(1)
counts_mat <- matrix(rpois(12, lambda = 50), nrow = 4)
rownames(counts_mat) <- c("GENE1", "GENE2", "GENE3", "GENE4")
colnames(counts_mat) <- paste0("sample", 1:3)

 rowData_gr <- GRanges(
  seqnames = c("chr1", "chr1", "chr2", "chr2"),
  ranges   = IRanges(start = c(11705000, 11730000, 5629000, 5640000),
                     width = 2000),
  strand   = c("+", "+", "-", "-")
)

se <- SummarizedExperiment(
  assays = list(counts = counts_mat),
  rowRanges = rowData_gr,
  colData = data.frame(condition = factor(c("control", "control", "treated")))
)

write.csv(counts(se), "counts.csv")
write.csv(as.data.frame(colData(se)), "sample_metadata.csv")
write.csv(as.data.frame(rowData(se)), "gene_metadata.csv")
```

The last call converts row-level metadata, including any genomic ranges stored in rowRanges, into a data frame before writing. Inspect the first file:

```bash
head -3 counts.csv
```

Expected output:

```
"","sample1","sample2","sample3"
"GENE1",44,60,50
"GENE2",56,52,43
```

The first column of row names is written because the default is `row.names = TRUE`. Keep it. Row names carry the gene identifiers, and a counts matrix without identifiers is useless. If a downstream tool rejects the quoted header, use `write.csv(counts(se), "counts.csv", quote = FALSE)`.

One caution with `write.csv()` and gene symbols. Spreadsheet software, and in some locales the CSV parsers behind it, will interpret symbols like `1-Mar` or `7-Sep` as calendar dates and destroy them. If your file will ever be opened in Excel, export a second copy using `write.table()` with `quote = FALSE` and instruct collaborators to import rather than double-click, or write a plain text TSV that most tools read safely.

### Step 6. Export Differential Expression Results

Differential expression tables are the most commonly shared result in expression genomics, and the export pattern is identical regardless of the tool that produced them. Using DESeq2 as the example:

```r
# Assuming dds is a fitted DESeqDataSet and res is a DESeqResults object
# res <- results(dds, contrast = c("condition", "treated", "control"))

res_df <- as.data.frame(res)
res_df$gene_id <- rownames(res_df)
write.csv(res_df, "deseq2_results.csv", row.names = FALSE)
```

Expected head of the output file:

```
"gene_id","baseMean","log2FoldChange","lfcSE","stat","pvalue","padj"
"GENE1",51.33,-0.12,0.41,-0.29,0.77,NA
```

Sort by adjusted p-value before writing so the file opens with the most significant hits at the top:

```r
res_df <- res_df[order(res_df$padj, na.last = TRUE), ]
```

### Step 7. Export Variant Calls as VCF

Variant data lives in a CollapsedVCF or ExpandedVCF object from the VariantAnnotation package. Writing to plain VCF is straightforward:

```r
library(VariantAnnotation)

vcf <- VCF(
  rowData = GRanges(c("chr1", "chr2"),
                    IRanges(start = c(11710500, 5630500),
                            width = 1)),
  colData = DataFrame(sample_id = c("sample1", "sample2")),
  fixed = DataFrame(
    REF = DNAStringSet(c("A", "G")),
    ALT = DNAStringSetList(c("G"), c("A"))
  ),
  geno = DataFrame(GT = matrix(c("0/1", "1/1"), nrow = 2))
)

writeVcf(vcf, "variants.vcf")
```

To write a compressed, indexable VCF, give the filename a `.bgz` extension and have Rsamtools installed:

```r
library(Rsamtools)
writeVcf(vcf, "variants.bgz")
indexTabix("variants.bgz", format = "vcf")
```

Downstream tools such as bcftools and tabix expect compressed VCFs to be block-gzip compressed and indexed. The `.bgz` route produces a file that both R and command-line tools can read. Plain `.vcf.gz` written with generic gzip will not be tabix-indexable, so use the bgzip path for anything you plan to share.

### Step 8. Save the Full State for Reproducibility

For collaborators who also use R, the fastest faithful export is an RDS file. RDS serializes a single R object with full fidelity, including all metadata columns, S4 class structure and attributes.

```r
saveRDS(se, "summarized_experiment.rds")
se_back <- readRDS("summarized_experiment.rds")
identical(assay(se), assay(se_back))
```

Expected output: `TRUE`.

This is not a substitute for open formats. It is a complement. Pair every RDS archive with the flat-file exports from the steps above so collaborators outside R are never locked out. The ReUseData project, developed to make genomic data management reproducible within R, addresses the same reproducibility gap at the pipeline level by turning data preprocessing scripts into standardized, portable Common Workflow Language data recipes that regenerate curated files in their generic formats [6].

## Exporting Data Pulled from Public Repositories

A large share of genomic work begins by downloading public data, and the export step often happens before your own analysis even starts. Two Bioconductor packages dominate this space for cancer genomics.

TCGAbiolinks provides a guided workflow to query, download and perform integrative analyses of data from The Cancer Genome Atlas, covering more than 10,000 tumor patients across 33 tumor types, and it was designed specifically to solve the data retrieval and integration challenges of that resource [7]. Later versions of the package added more flexible pipelines for the same retrieval-and-harmonization role [3]. In practice, its `GDCprepare()` function materializes downloaded data into a SummarizedExperiment in your session, at which point every export pattern from the previous section applies directly.

The GenomicDataCommons package provides a Bioconductor interface to the NCI Genomic Data Commons, a unified repository spanning TCGA, TARGET and other cancer studies, and exposes query and access functions that other developers build upon [4]. When you pull files through GenomicDataCommons, the raw files such as BAMs, VCFs and expression matrices are already on disk in their native formats. Your export job is then to keep the file manifest, usually via a data frame saved with `write.csv()`, alongside the files so provenance travels with the data.

The same retrieval-then-export logic generalizes. CAGEfightR, for example, imports data from BigWig files to analyze transcription start sites and enhancers, and because it is built on standard Bioconductor classes, its results such as quantified TSS counts and enhancer coordinates export through the same rtracklayer and write.csv patterns used throughout this guide [8].

## Specialized Data Types and Their Export Paths

Not every genomic object exports through a single file. Three cases deserve explicit treatment.

### Genomic Interactions

Chromatin interaction data from experiments such as Hi-C and ChIA-PET represents pairs of genomic loci rather than single intervals. The InteractionSet package provides the Bioconductor classes that represent these interactions and their experimental data, and it is the infrastructure layer used by higher-level packages [9]. GenomicInteractions builds on this foundation for processing, annotating and visualizing chromosome conformation capture data [5]. To export interaction data for external tools, extract the anchor regions and the counts separately:

```r
# Assuming gi is a GInteractions object
anchor1 <- as.data.frame(regions(gi)) # or extract anchors per interaction
write.csv(as.data.frame(interactions(gi)), "interactions.csv")
```

Long-range interaction tools in the Bioconductor ecosystem, such as r3Cseq for 3C-seq analysis, produce candidate interaction regions with statistical significance, and those region tables export as BED or CSV using the same patterns as Step 2 [10].

### Region Sets Bound for Enrichment Tools

When your destination is a functional enrichment tool for genomic regions, coordinate format matters. The rGREAT package implements the GREAT algorithm locally and supports more than 500 organisms with user-provided gene sets and backgrounds [11]. Export your regions as BED and confirm the genome build matches the annotation the enrichment tool uses. A region set exported against one genome assembly and analyzed against another produces silently wrong results.

### Coordinate Conversion Between Assemblies

If you need the same feature set on two genome builds, convert coordinates rather than re-deriving them. The CTCF data package, which collects strand-oriented CTCF binding sites for human and mouse genomes including newer assemblies, demonstrates that liftOver-based conversion between assemblies is a viable, recommended strategy for keeping binding site coordinates consistent across genome versions [12]. In R, the rtracklayer `liftOver()` function performs this conversion using chain files you download separately:

```r
# chain file downloaded from the UCSC downloads area
# gr_new <- liftOver(gr, "hg38ToHg19.over.chain")
```

Keep the source assembly recorded in every exported file, because a BED file with no assembly annotation is ambiguous by design.

## Choosing the Right Export Format

![Decision path asking what kind of data you hold and routing intervals to BED, signal to bigWig, variants to compressed VCF.](/article-images/illustrations/export-genomic-data-r-bioconductor-format-routing.webp)

The table below summarizes the mapping between data type, format, R function and typical consumer. Use it as a routing guide when someone asks for "the data" without specifying a format.

| Data in R | Export format | Function | Typical consumer |
|--|--|--|--|
| GRanges of intervals | BED | `rtracklayer::export()` | bedtools, IGV, UCSC browser |
| Numeric genome-wide signal | bigWig | `rtracklayer::export(format="bigWig")` | Genome browsers, deepTools |
| Gene models and annotations | GFF3 or GTF | `rtracklayer::export()` | STAR, featureCounts, GENCODE tools |
| Count matrices and results tables | CSV or TSV | `write.csv()`, `write.table()` | Spreadsheets, Python, reviewers |
| Variant calls | VCF, block-gzipped VCF | `VariantAnnotation::writeVcf()` | bcftools, GATK, IGV |
| Aligned reads | BAM | downstream of Rsamtools workflows | Most aligners and viewers |
| Full R objects | RDS | `saveRDS()` | Other R users |
| Genome-browser overlays | track hubs via rtracklayer | `browserSession()`, `track()` | UCSC Genome Browser |

Two of these rows connect to visualization-oriented packages worth knowing. Gviz provides genome-browser style visualization within R, so some analyses that seem to need an export actually need only a plot [13]. karyoploteR creates customizable linear whole-genome plots with arbitrary data laid over chromosomes, which is often the fastest way to satisfy a figure request that would otherwise require exporting data to a drawing tool [14]. EnrichedHeatmap visualizes how genomic signals are enriched around target regions and supports parallel heatmaps integrating methylation, expression and histone modification data, again reducing the need to hand off raw files for visualization [15]. Export when you must share data. Plot when you must share a conclusion.

## Tips for Clean, Reproducible Exports

These tips come from repeated failure modes in real handoffs. Each one prevents a specific class of downstream error.

**Record the genome build everywhere.** Add genome information to your GRanges before export with `seqinfo()` and `genome(gr) <- "hg38"`. rtracklayer writes assembly information into BED headers when you enable track lines via `trackLine = TRUE`, and many formats carry it natively. Files without assembly metadata cause silent coordinate mismatches.

**Harmonize chromosome naming before export.** UCSC conventions use `chr1`, Ensembl conventions use `1`. If your export destination expects the other style, convert with `seqlevelsStyle()` from the GenomeInfoDb package before writing. A BED file mixing both styles breaks intersect operations in bedtools and produces empty browser tracks.

**Verify by round-tripping.** The strongest check is to import your own file back and compare:

```r
gr_check <- import("peaks.bed", format = "BED")
identical(seqnames(gr), seqnames(gr_check))
all(start(gr) == start(gr_check) + 1)  # BED is 0-based, R is 1-based
```

Expected output: `TRUE` for both lines. If the round trip fails, the file is wrong before it ever leaves your machine.

**Sort and compress large interval files.** Before writing big BED or GTF files destined for indexed tools, sort with `sort(gr)` and consider `sortchrom` behavior for chromosome ordering. Sorted input is a precondition for tabix indexing and bigWig conversion.

**Use biomaRt to attach stable identifiers before export.** When your results table carries probe IDs, transcript versions or Ensemble IDs, map them to consistent gene identifiers first. The biomaRt package uses BioMart web services to provide programmable, reproducible mappings between probe and target molecules, and it documents the gene-to-transcript-to-protein mapping problems that commonly complicate integration [16]. Exporting a table with unmapped or inconsistent identifiers forces every collaborator to redo that mapping, differently.

**Check quality before you share.** For comparative genomics outputs such as orthogroup inference or synteny detection, the cogeqc package provides a toolkit for assessing data quality before results move downstream, comparing assembly and annotation statistics against closely related species and scoring orthogroup and synteny results [17]. Exporting an assessed, validated dataset is far cheaper than retracting a shared file later.

**Write a companion README.** For any exported dataset, include a plain-text file listing the genome assembly, the R and Bioconductor versions, the exact commands used, and a checksum such as `md5sum peaks.bed` output. This mirrors the reproducibility emphasis running through the Bioconductor data management literature [6].

## Common Mistakes and Limitations

These are the errors that account for most failed genomic data handoffs. Each includes the failure mode you will actually see and the fix.

**Hand-writing BED files with write.table().** The 0-based half-open BED convention versus the 1-based fully closed R convention causes a one-base shift at every start coordinate. If you write `write.table(as.data.frame(gr), "peaks.bed", ...)` directly, every interval starts one base late. rtracklayer's `export()` handles the conversion. Never construct coordinate files by hand from GRanges columns unless you deliberately apply the offset yourself and document it.

**Forgetting that BED strips metadata columns.** The core BED format holds six columns: chromosome, start, end, name, score and strand. A GRanges with ten metadata columns exported to plain BED loses four of them. Either use `format = "BED15"` for extended fields, use GFF3 with rich attributes, or export the full table separately as CSV and treat the BED as a coordinate index only.

**Exporting unsorted or overlapping ranges as bigWig.** The bigWig writer requires sorted, non-overlapping intervals. The failure appears as an error from the UCSC conversion library complaining about input ordering, and the fix is `export(sort(gr), "x.bigWig")`. Resolve overlaps explicitly with `reduce()` or `disjoin()` when the signal model requires it.

**Losing gene symbols to spreadsheet date conversion.** Symbols such as `1-Mar` and `9-Sep` become calendar dates when a CSV is double-clicked into Excel. The damage is invisible in the saved file until someone notices thousands of missing genes. Export a TSV with `write.table(..., sep = "\t", quote = FALSE)` and document that the file should be imported, not opened directly.

**Dropping row names with row.names = FALSE.** In expression tables, `write.csv(df, row.names = FALSE)` on a data frame whose row names are gene IDs produces a file with no identifiers. Move row names into an explicit column first, as shown in Step 6, before any `row.names = FALSE` call.

**VCF compression confusion.** Writing to `.vcf.gz` with generic compression produces a file that bcftools reads but tabix cannot index, because tabix requires block gzip. Use the `.bgz` route shown in Step 7. The typical failure surfaces later as an index error from `tabix -p vcf` or from a downstream tool that expects the `.tbi` index file.

**Ignoring Bioconductor and R version drift.** Bioconductor packages are versioned against specific R releases, and packages undergo continuous automated testing within the project's formal review process [1]. A script that works on one version can fail on another after a class definition changes. Record `sessionInfo()` output alongside your exports:

```r
capture.output(sessionInfo(), file = "session_info.txt")
```

**Assuming export preserves everything.** Some formats are lossy by design. GTF has no explicit phase concept for all feature types, BED has no strand-independent orientation field, and VCF flattens some multi-allelic representations. After export, compare object and file counts:

```r
length(gr)            # intervals in R
length(readLines("peaks.bed")) - 1  # minus track line, if any
```

These should match before you declare the export complete.

**One limitation to keep in view throughout.** Export functions move data, they do not validate biology. A perfectly formatted BED file of peaks called against the wrong genome build, or a counts matrix joined to mismatched sample metadata, exports cleanly and misleads every consumer. Coordinate conversion between assemblies, as the CTCF binding site work shows, is a real and necessary step whenever genome versions change, and it must be planned rather than assumed [12].

## Frequently Asked Questions

### What is the fastest way to export a GRanges object as a BED file?

Use `rtracklayer::export(gr, "peaks.bed", format = "BED")`. This handles the one-based to zero-based coordinate conversion automatically and preserves the first six BED fields including name, score and strand.

### How do I export DESeq2 results to a spreadsheet?

Convert the results object with `as.data.frame(res)`, move row names into an explicit `gene_id` column, and write with `write.csv(res_df, "deseq2_results.csv", row.names = FALSE)`. Sort by adjusted p-value before writing so the significant hits appear at the top.

### Which file format should I use for genome browser tracks?

Use bigWig for continuous numeric signal such as coverage, and BED for discrete intervals such as peak calls. Both load directly into IGV and the UCSC Genome Browser, and both are written by `rtracklayer::export()`.

### How do I export a SummarizedExperiment with counts and metadata?

Write the three components separately: the assay matrix with `write.csv(counts(se), "counts.csv")`, the sample metadata with `write.csv(as.data.frame(colData(se)), "sample_metadata.csv")`, and the feature data with `write.csv(as.data.frame(rowData(se)), "gene_metadata.csv")`. Splitting them preserves all information without forcing one format to carry three data types.

### Can I export VCF files directly from R?

Yes. Use `VariantAnnotation::writeVcf()` to write plain VCF, or write to a `.bgz` extension with Rsamtools installed to produce block-gzipped, tabix-indexable output that command-line tools can index and query.

### How do I handle chromosome naming differences like chr1 versus 1?

Convert seqlevel styles with `seqlevelsStyle()` from the GenomeInfoDb package before export, and match the convention your destination tool expects. Mixing UCSC-style and Ensembl-style names in one file breaks interval operations and produces empty genome browser tracks.

### How do I save my entire Bioconductor analysis for another R user?

Use `saveRDS(object, "file.rds")` for single objects, which preserves full class structure and metadata, and have the recipient read it back with `readRDS()`. Pair the RDS archive with open-format exports so non-R users are not excluded, and record `sessionInfo()` output for version provenance.

### How do I export data I downloaded from TCGA or the GDC?

If you used TCGAbiolinks, the `GDCprepare()` function returns a SummarizedExperiment that exports with the patterns in this guide. If you used GenomicDataCommons, your files are already on disk in native formats, so export the download manifest as a CSV to keep provenance attached to the files.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is the fastest way to export a GRanges object as a BED file?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Use rtracklayer::export(gr, \"peaks.bed\", format = \"BED\"). This handles the one-based to zero-based coordinate conversion automatically and preserves the first six BED fields including name, score and strand."
      }
    },
    {
      "@type": "Question",
      "name": "How do I export DESeq2 results to a spreadsheet?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Convert the results object with as.data.frame(res), move row names into an explicit gene_id column, and write with write.csv(res_df, \"deseq2_results.csv\", row.names = FALSE). Sort by adjusted p-value before writing so the significant hits appear at the top."
      }
    },
    {
      "@type": "Question",
      "name": "Which file format should I use for genome browser tracks?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Use bigWig for continuous numeric signal such as coverage, and BED for discrete intervals such as peak calls. Both load directly into IGV and the UCSC Genome Browser, and both are written by rtracklayer::export()."
      }
    },
    {
      "@type": "Question",
      "name": "How do I export a SummarizedExperiment with counts and metadata?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Write the three components separately: the assay matrix with write.csv(counts(se), \"counts.csv\"), the sample metadata with write.csv(as.data.frame(colData(se)), \"sample_metadata.csv\"), and the feature data with write.csv(as.data.frame(rowData(se)), \"gene_metadata.csv\"). Splitting them preserves all information without forcing one format to carry three data types."
      }
    },
    {
      "@type": "Question",
      "name": "Can I export VCF files directly from R?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Use VariantAnnotation::writeVcf() to write plain VCF, or write to a .bgz extension with Rsamtools installed to produce block-gzipped, tabix-indexable output that command-line tools can index and query."
      }
    },
    {
      "@type": "Question",
      "name": "How do I handle chromosome naming differences like chr1 versus 1?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Convert seqlevel styles with seqlevelsStyle() from the GenomeInfoDb package before export, and match the convention your destination tool expects. Mixing UCSC-style and Ensembl-style names in one file breaks interval operations and produces empty genome browser tracks."
      }
    },
    {
      "@type": "Question",
      "name": "How do I save my entire Bioconductor analysis for another R user?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Use saveRDS(object, \"file.rds\") for single objects, which preserves full class structure and metadata, and have the recipient read it back with readRDS(). Pair the RDS archive with open-format exports so non-R users are not excluded, and record sessionInfo() output for version provenance."
      }
    },
    {
      "@type": "Question",
      "name": "How do I export data I downloaded from TCGA or the GDC?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "If you used TCGAbiolinks, the GDCprepare() function returns a SummarizedExperiment that exports with the patterns in this guide. If you used GenomicDataCommons, your files are already on disk in native formats, so export the download manifest as a CSV to keep provenance attached to the files."
      }
    }
  ]
}
</script>

## Sources

1. [Orchestrating high-throughput genomic analysis with Bioconductor](https://pubmed.ncbi.nlm.nih.gov/25633503/)
2. [Bioconductor's Computational Ecosystem for Genomic Data Science in Cancer.](https://pubmed.ncbi.nlm.nih.gov/40779102/)
3. [Analyses of cancer data in the Genomic Data Commons Data Portal with new functionalities in the TCGAbiolinks R/Bioconductor package](https://doi.org/10.1101/350439)
4. [GenomicDataCommons: a Bioconductor Interface to the NCI Genomic Data Commons](https://doi.org/10.1101/117200)
5. [GenomicInteractions: An R/Bioconductor package for manipulating and investigating chromatin interaction data.](https://pubmed.ncbi.nlm.nih.gov/26576536/)
6. [ReUseData: an R/Bioconductor tool for reusable and reproducible genomic data management](https://pubmed.ncbi.nlm.nih.gov/38172657/)
7. [TCGAbiolinks: an R/Bioconductor package for integrative analysis of TCGA data](https://pubmed.ncbi.nlm.nih.gov/26704973/)
8. [CAGEfightR: analysis of 5′-end data using R/Bioconductor](https://pubmed.ncbi.nlm.nih.gov/31585526/)
9. [Infrastructure for genomic interactions: Bioconductor classes for Hi-C, ChIA-PET and related experiments.](https://pubmed.ncbi.nlm.nih.gov/27303634/)
10. [r3Cseq: an R/Bioconductor package for the discovery of long-range genomic interactions from chromosome conformation capture and next-generation sequencing data](https://pubmed.ncbi.nlm.nih.gov/23671339/)
11. [rGREAT: an R/bioconductor package for functional enrichment on genomic regions](https://pubmed.ncbi.nlm.nih.gov/36394265/)
12. [CTCF: an R/bioconductor data package of human and mouse CTCF binding sites](https://pubmed.ncbi.nlm.nih.gov/36699364/)
13. [Visualizing Genomic Data Using Gviz and Bioconductor](https://pubmed.ncbi.nlm.nih.gov/27008022/)
14. [karyoploteR: an R/Bioconductor package to plot customizable genomes displaying arbitrary data](https://pubmed.ncbi.nlm.nih.gov/28575171/)
15. [EnrichedHeatmap: an R/Bioconductor package for comprehensive visualization of genomic signal associations](https://pubmed.ncbi.nlm.nih.gov/29618320/)
16. [Mapping Identifiers for the Integration of Genomic Datasets with the R/Bioconductor package biomaRt](https://pubmed.ncbi.nlm.nih.gov/19617889/)
17. [Assessing the quality of comparative genomics data and results with the cogeqc R/Bioconductor package](https://doi.org/10.1111/2041-210X.14243)