Skip to main content
Lazy, streaming filesystem utilities for JavaScript. This package provides utilities for working with files on the local filesystem using the LazyFile/native File API.

Features

  • Web Standards - Uses LazyFile which matches the native File API
  • Seamless Node.js Compat - Works seamlessly with Node.js file descriptors and handles
  • Lazy Loading - Files are only read when needed
  • Streaming - Supports streaming file content

Installation

npm install remix

API Reference

openLazyFile

Open a lazy file from the filesystem.
path
string
required
Path to the file to open
options
LazyFileOptions
Options to override file metadata

LazyFileOptions

name
string
Override the file name. Defaults to the basename of the path.
type
string
Override the MIME type. Defaults to detected type based on extension.
lastModified
number
Override the last modified timestamp in milliseconds. Defaults to file’s mtime.

Returns

lazyFile
LazyFile
A lazy file that implements the File API

writeFile

Write a file or blob to the filesystem.
destination
string | FileHandle
required
Path or file handle to write to
data
Blob | LazyFile
required
Data to write

Returns

promise
Promise<void>
Promise that resolves when the file has been written

Usage Examples

Opening Files

Open a file and read its contents:
import { openLazyFile } from 'remix/fs'

// Open a file from the filesystem
let lazyFile = openLazyFile('./path/to/file.json')

// The file is lazy - no data is read until you access it
let json = JSON.parse(await lazyFile.text())
console.log(json)

// Read as bytes
let bytes = await lazyFile.bytes()

// Get a readable stream
let stream = lazyFile.stream()

Custom Metadata

Override file metadata:
import { openLazyFile } from 'remix/fs'

let lazyFile = openLazyFile('./image.jpg', {
  name: 'custom-name.jpg',
  type: 'image/jpeg',
  lastModified: Date.now(),
})

console.log(lazyFile.name) // 'custom-name.jpg'
console.log(lazyFile.type) // 'image/jpeg'

Writing Files

Write files to the filesystem:
import { openLazyFile, writeFile } from 'remix/fs'

// Read a file and write it elsewhere
let lazyFile = openLazyFile('./source.txt')
await writeFile('./destination.txt', lazyFile)

Using File Handles

Work with Node.js file handles:
import { openLazyFile, writeFile } from 'remix/fs'
import * as fsp from 'node:fs/promises'

// Open a file handle
let handle = await fsp.open('./destination.txt', 'w')

// Write to the handle
let lazyFile = openLazyFile('./source.txt')
await writeFile(handle, lazyFile)

// Close the handle
await handle.close()

Serving Files in HTTP Responses

Serve files in HTTP responses:
import { openLazyFile } from 'remix/fs'
import { createFileResponse } from 'remix/response/file'
import { createRouter } from 'remix/fetch-router'

let router = createRouter()

router.get('/download/:filename', async ({ params, request }) => {
  let lazyFile = openLazyFile(`./uploads/${params.filename}`)
  return createFileResponse(lazyFile, request)
})

File Upload Storage

Store uploaded files to the filesystem:
import { writeFile } from 'remix/fs'
import { parseFormData } from 'remix/form-data-parser'
import { createRouter } from 'remix/fetch-router'

let router = createRouter()

router.post('/upload', async ({ request }) => {
  let formData = await parseFormData(request, {
    uploadHandler: async (fileUpload) => {
      let path = `./uploads/${Date.now()}-${fileUpload.name}`
      await writeFile(path, fileUpload)
      return path
    },
  })

  let filePath = formData.get('file')
  return Response.json({ filePath })
})

Stream Processing

Process files as streams:
import { openLazyFile } from 'remix/fs'

let lazyFile = openLazyFile('./large-file.json')
let stream = lazyFile.stream()

// Process the stream
for await (let chunk of stream) {
  // Process each chunk
  console.log('Chunk size:', chunk.byteLength)
}

Performance

Lazy files are designed for efficiency:
  • No upfront I/O - Files are not read until accessed
  • Streaming - Large files can be streamed in chunks
  • Minimal memory - Only active chunks are kept in memory

Best Practices

  • Use lazy files for large files to avoid loading entire file into memory
  • Stream files when serving over HTTP for better memory usage
  • Close file handles when done to free resources
  • Handle errors when reading files that may not exist

Lazy File

Lazy, streaming File implementation

File Storage

Storage abstraction for files

Build docs developers (and LLMs) love