---
title: "Generate in memory"
description: "Run a generator on a virtual filesystem with mem, and read the result back from the volume."
source: "https://jostraca.org/how-to/generate-in-memory/"
---

# Generate in memory

Run a generator on a virtual filesystem with mem, and read the result back from the volume.

Rendered from [`docs/how-to/generate-in-memory.md`](https://github.com/jostraca/jostraca/blob/master/docs/how-to/generate-in-memory.md) in the generator repository — where a correction belongs, and where the test suite runs every example on this page or states why it does not.

`mem: true` runs the whole generate on an in-memory filesystem. Nothing touches disk, and the result carries `vol()` so you can read back what was written.

```js
import { Jostraca, Project, Folder, File, Content } from 'jostraca'

const jostraca = Jostraca({ mem: true })

const res = await jostraca.generate({ folder: '/out' }, () => {
  Project({ folder: 'app' }, () => {
    File({ name: 'index.js' }, () => Content('// entry\n'))
    Folder({ name: 'src' }, () => {
      File({ name: 'lib.js' }, () => Content('// lib\n'))
    })
  })
})

const vol = res.vol().toJSON()
const paths = Object.keys(vol).filter((p) => !p.includes('/.jostraca/'))
console.log(JSON.stringify(paths.sort()))
console.log(JSON.stringify(vol['/out/app/index.js']))
```

```text
["/out/app/index.js","/out/app/src/lib.js"]
"// entry\n"
```

Use an absolute output folder in memory mode. A relative one resolves against the process working directory, so the volume keys come back prefixed with wherever the process happened to be.

Seed input files with `vol`, which is how a fragment or a copy source gets there without a temp directory:

```js
import { Jostraca, Project, File, Fragment } from 'jostraca'

const jostraca = Jostraca({
  mem: true,
  vol: { '/tpl/header.txt': 'HEADER\n' },
})

const res = await jostraca.generate({ folder: '/out' }, () => {
  Project({}, () => {
    File({ name: 'a.txt' }, () => Fragment({ from: '/tpl/header.txt' }))
  })
})

console.log(JSON.stringify(res.vol().toJSON()['/out/a.txt']))
```

```text
"HEADER\n"
```

Three rules about the pairing, because they are not symmetrical:

-   **`vol` without `mem` does nothing.** No virtual filesystem is built and the run goes to the real one. This is the mistake to check first when a memory-mode test writes real files.
-   **A global `mem: true` with no per-call `vol` shares one volume** for the life of the instance, so state accumulates across `generate()` calls. That is useful for a two-run test and surprising otherwise.
-   **A per-call `vol` forks**: it seeds a fresh volume from the global seed merged with yours, and that call’s writes never reach the shared one.

The in-memory filesystem is part of jostraca. Nothing is installed for it, and it is not a filesystem you can pass around outside a run.

The Go port takes the same pair: `WithMem()` switches the in-memory filesystem on and `WithVol()` seeds it, and the result carries `Vol` and `FS`. `WithFS(NewMemFS())` is still available when you want to seed the provider by writing into it. The [Go reference](https://jostraca.org/docs/reference-go#withmem-and-withvol) shows both, along with the three rules they share with TypeScript.

Before v0.35.0 both Go options were inert—a generator configured with them wrote to the real filesystem and returned `nil` for `Vol` and `FS`, with no error.

## See also

-   [Test a generator](https://jostraca.org/how-to/test-a-generator) for the pattern this enables.
-   [Options reference](https://jostraca.org/docs/reference-options#in-memory-generation).
