Every JBrowseR function that accepts data takes a URL. Genomics files are far too large to inline as Shiny static resources, and the browser fetches only the slices it needs directly from the host — so the data lives at a URL and JBrowse reads from it in place.

For human and model organisms you often need no hosting at all: pass a hub name straight to JBrowseR() and the assembly, reference-name aliases, cytobands, and gene-name search all load from the CORS-enabled hub at jbrowse.org.

JBrowseR(assembly = "hg38", location = "BRCA1")

For your own data you host the files yourself. On the JBrowse 2 team we use Amazon S3 — each object has its own URL — but any web server works, e.g. Apache or a cloud bucket.

Server requirements

Whichever host you pick, it must satisfy two requirements:

  • HTTP Range requests, so the browser can use byte serving to fetch only the chunks needed to render the current view instead of the whole file.
  • CORS, because the request originates from wherever the browser is running, not from where the data is hosted.

Here is an example CORS configuration for an S3 bucket:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "Accept-Ranges",
            "Content-Range",
            "Content-Encoding",
            "Content-Length"
        ],
        "MaxAgeSeconds": 3000
    }
]

If you use S3 and plan to deploy with shinyapps.io, put the bucket in Amazon’s US-East region — shinyapps.io is hosted entirely there, so co-locating the data gives faster performance.

Viewing local files

Files on your own machine need no host at all. local_files reads them into the document, and a track then refers to one by name exactly as it would a URL:

JBrowseR(
  assembly = "hg38",
  tracks = list(list(uri = "peaks.bed.gz", name = "Peaks")),
  local_files = "~/data/peaks.bed.gz",
  location = "chr1:1-10000"
)

The name is the file’s basename, so the .bed.gz extension still picks the adapter. A conventional sibling index next to the file — .tbi, .csi, .bai, .crai, .fai, .gzi — is registered alongside it under the name the adapter derives, so an indexed file stays indexed: the browser seeks into the bytes it holds and reads only the region on screen, the same as it would over HTTP.

This is the one case where no server is involved, so the two requirements above do not apply — there is no origin to configure CORS for, and the range reads happen inside the browser. It is also what makes a knitted document self-contained: the bytes travel with the HTML, where a http://localhost:... URL would be dead for anyone you send it to.

The cost is that the bytes ride inside the document, base64-encoded, rather than being fetched a slice at a time. That is fine for a file on an analyst’s laptop and wrong for a reference genome — local_files warns past ~50 MB. Host anything larger and pass its URL.

An assembly can come from a local file the same way, since uri is a name here like any other:

JBrowseR(
  assembly = list(name = "mine", uri = "genome.fa.gz"),
  local_files = c("~/data/genome.fa.gz", "~/data/genes.gff.gz"),
  tracks = list(list(uri = "genes.gff.gz", name = "Genes"))
)