# Set Up the Filesystem
URL: /docs/guides/filesystem-setup



Set Up the Filesystem [#set-up-the-filesystem]

Configure the filesystem backend that kernels use to read project files. The framework provides three built-in constructors: `fromNodeFS` for disk access, `fromMemoryFS` for in-memory content, and `fromFsLike` for any fs-compatible object (BrowserFS, memfs, polyfills).

Prerequisites [#prerequisites]

* [Install @taucad/runtime](../getting-started/installation)
* Completed the [Quick Start](../getting-started/quick-start)

Goal [#goal]

Choose and configure a filesystem implementation so your runtime client can read (and optionally write) project files during render, export, and parameter extraction.

Steps [#steps]

1. Import Filesystem Constructors [#1-import-filesystem-constructors]

`fromMemoryFS` and `fromFsLike` are available from the main entry. `fromNodeFS` requires the Node.js subpath (it depends on Node.js APIs):

```typescript
import { fromMemoryFS, fromFsLike } from '@taucad/runtime';
import { fromNodeFS } from '@taucad/runtime/filesystem/node';
```

2. Use fromNodeFS for Disk-Based Projects [#2-use-fromnodefs-for-disk-based-projects]

Use `fromNodeFS` when your project files live on disk. Pass the base path; all file operations are resolved relative to it. Requires Node.js (not available in browser projects).

```typescript
import { createRuntimeClient } from '@taucad/runtime';
import { fromNodeFS } from '@taucad/runtime/filesystem/node';
import { replicad } from '@taucad/runtime/kernels';
import { esbuild } from '@taucad/runtime/bundler';

const client = createRuntimeClient({
  kernels: [replicad()],
  bundlers: [esbuild()],
  fileSystem: fromNodeFS('/path/to/project'),
});
```

Use this when running in Node.js (CLI, tests, server-side) and when you need persistent cache (e.g., geometry cache, parameter cache).

3. Use fromMemoryFS for In-Memory Content [#3-use-frommemoryfs-for-in-memory-content]

Use `fromMemoryFS` when file content is passed directly (e.g., from an editor) or when you want no disk I/O. Optionally seed with initial files:

```typescript
import { createRuntimeClient, fromMemoryFS } from '@taucad/runtime';
import { replicad } from '@taucad/runtime/kernels';
import { esbuild } from '@taucad/runtime/bundler';

const filesystem = fromMemoryFS({
  'main.ts': `
    import { drawRoundedRectangle } from 'replicad';
    export default function main() {
      return drawRoundedRectangle(30, 50, 5).sketchOnPlane('XY').extrude(10);
    }
  `,
  'lib/utils.ts': 'export function helper() { return 42; }',
});

const client = createRuntimeClient({
  kernels: [replicad()],
  bundlers: [esbuild()],
  fileSystem: filesystem,
});
```

4. Use fromFsLike for Any fs-Compatible Object [#4-use-fromfslike-for-any-fs-compatible-object]

Use `fromFsLike` when you have an fs-compatible object with a `promises` namespace (e.g., BrowserFS, memfs, or any polyfill). The `FsLike` interface requires `promises.readFile`, `promises.writeFile`, `promises.mkdir`, and the other standard `fs.promises` methods:

```typescript @ts-nocheck
import { createRuntimeClient, fromFsLike } from '@taucad/runtime';
import { replicad } from '@taucad/runtime/kernels';
import { esbuild } from '@taucad/runtime/bundler';
import { BFSRequire } from 'browserfs';

const fs = BFSRequire('fs');
const filesystem = fromFsLike(fs, '/');

const client = createRuntimeClient({
  kernels: [replicad()],
  bundlers: [esbuild()],
  fileSystem: filesystem,
});
```

5. Understand RuntimeFileSystemBase vs RuntimeFileSystem [#5-understand-runtimefilesystembase-vs-runtimefilesystem]

The framework uses two filesystem interfaces:

**`RuntimeFileSystemBase`** -- The 11-method base interface that `fromNodeFS`, `fromMemoryFS`, and `fromFsLike` return. Matches `fs.promises` semantics: `readFile`, `writeFile`, `mkdir`, `readdir`, `unlink`, `rmdir`, `rename`, `stat`, `lstat`, `exists`.

**[`RuntimeFileSystem`](../api/filesystem)** -- An enhanced interface that extends the base with convenience methods. The framework wraps the base automatically via `createRuntimeFileSystem(base)`:

| Method            | Signature                                          | Default Implementation                       |
| ----------------- | -------------------------------------------------- | -------------------------------------------- |
| `readFiles`       | `(paths) => Promise<Record<string, Uint8Array>>`   | `Promise.all(paths.map(readFile))`           |
| `readdirContents` | `(dirPath) => Promise<Record<string, Uint8Array>>` | `readdir` + `stat` + `readFile` (files only) |
| `readdirStat`     | `(dirPath) => Promise<FileStatEntry[]>`            | `readdir` + `stat` per entry                 |
| `ensureDir`       | `(path) => Promise<void>`                          | `mkdir(path, { recursive: true })`           |

All paths are absolute. Backends can supply optimized overrides for any enhanced method (e.g., batch reads at the storage layer).

6. Use Filesystem Bridges for Cross-Worker Communication [#6-use-filesystem-bridges-for-cross-worker-communication]

For advanced setups where the filesystem lives in a different worker or the main thread, use the bridge utilities from `@taucad/runtime/filesystem`:

```typescript @ts-nocheck
import { createBridgePort, exposeFileSystem, createFileSystemBridge } from '@taucad/runtime/filesystem';
```

**`createBridgePort(fileSystem)`** -- Creates a `MessagePort` bridge to a filesystem implementation. Returns a `BridgeHandle` with `{ port, dispose() }`. The port can be transferred to a worker:

```typescript @ts-nocheck
import { createBridgePort } from '@taucad/runtime/filesystem';
import { fromNodeFS } from '@taucad/runtime/filesystem/node';

const fileSystem = fromNodeFS('/path/to/project');
const { port, dispose } = createBridgePort(fileSystem);
// Transfer port to a worker, then call dispose() when done
```

**`exposeFileSystem(handlers, options?)`** -- Expose a filesystem to incoming bridge connections. Returns an `ExposeFileSystemHandle`.

**`createFileSystemBridge(handlers, options?)`** -- Higher-level helper that creates a MessageChannel and transfers a port to a worker. Returns `{ port, dispose }`.

Call `dispose()` when the bridge is no longer needed to release the underlying MessagePort resources.

When to Use Each [#when-to-use-each]

| Constructor                 | Use when                                                   |
| --------------------------- | ---------------------------------------------------------- |
| `fromNodeFS(basePath)`      | Node.js environment, disk-based projects, persistent cache |
| `fromMemoryFS(files?)`      | Editor-driven content, tests, no disk I/O, ephemeral cache |
| `fromFsLike(fs, rootPath?)` | Any fs-compatible object (BrowserFS, memfs, polyfills)     |

Variations [#variations]

* **Custom implementation**: Implement `RuntimeFileSystemBase` directly for custom backends (e.g., cloud storage, virtual mounts). See [API Reference: Filesystem](../api/filesystem) for the full interface.
* **Filesystem bridge**: For worker-to-worker filesystem access, use `createBridgePort` and `createFileSystemBridge` from `@taucad/runtime/filesystem`.

Related [#related]

* [Use Middleware](./using-middleware) -- Caching middleware requires a writable filesystem
* [Worker Model](../concepts/worker-model) -- How the filesystem is bridged to the worker
* [API Reference: Filesystem](../api/filesystem) -- Full filesystem API reference
* [API Reference: Client](../api/client) -- createRuntimeClient filesystem option
