Skip to content

fs

The fs package provides filesystem utilities built on the web File API. It bridges the gap between Node.js filesystem operations and web-standard File objects used throughout Remix.

Installation

The filesystem utilities are included with Remix. No additional installation is needed.

Import

ts
import { openLazyFile, writeFile } from 'remix/fs'

API

openLazyFile(path)

Creates a LazyFile from a file on disk. The file's content is not read until it is accessed. Metadata (name, size, MIME type, last modified) is read immediately from the filesystem.

ts
function openLazyFile(path: string): Promise<LazyFile>
ts
let file = await openLazyFile('./uploads/photo.jpg')

console.log(file.name)         // 'photo.jpg'
console.log(file.type)         // 'image/jpeg'
console.log(file.size)         // 1048576
console.log(file.lastModified) // 1704067200000

// Content is read lazily
let stream = file.stream()

writeFile(path, file)

Writes a File (or Blob) to the specified path on disk. Parent directories are created automatically if they do not exist.

ts
function writeFile(path: string, file: File | Blob): Promise<void>
ts
let file = new File(['Hello, world!'], 'hello.txt', { type: 'text/plain' })
await writeFile('./output/hello.txt', file)

Examples

Serve a File from Disk

ts
import { openLazyFile } from 'remix/fs'
import { createFileResponse } from 'remix/response/file'

router.map(fileRoute, async ({ request, params }) => {
  let file = await openLazyFile(`./uploads/${params.filename}`)
  return createFileResponse(file, request)
})

The file is streamed to the client without being buffered in memory. createFileResponse automatically handles ETag headers, conditional requests, and byte-range requests.

Save an Uploaded File

ts
import { parseFormData, FileUpload } from 'remix/form-data-parser'
import { writeFile } from 'remix/fs'

router.map(uploadRoute, async ({ request }) => {
  let formData = await parseFormData(request)
  let upload = formData.get('file') as FileUpload

  await writeFile(`./uploads/${upload.name}`, upload)

  return new Response('Saved')
})

Copy a File

ts
import { openLazyFile, writeFile } from 'remix/fs'

let file = await openLazyFile('./source/document.pdf')
await writeFile('./backup/document.pdf', file)

Generate and Write a File

ts
import { writeFile } from 'remix/fs'

let csv = 'name,email\nAlice,alice@example.com\nBob,bob@example.com'
let file = new File([csv], 'users.csv', { type: 'text/csv' })

await writeFile('./exports/users.csv', file)
  • lazy-file --- Deferred file reading.
  • file-storage --- Key/value file storage abstraction.
  • response --- File response helpers with ETag and range support.

Released under the MIT License.