NOTE: these docs are deprecated. Please see our new Subhosting docs site here instead.
Virtual Filesystem
Isolates hosted on Deno Deploy Subhosting have a virtual read-only file system. The contents of this file system is controlled entirely by the subhoster, through origin RPC endpoints.
The APIs to interact with this file system are nearly identical to the ones in the Deno CLI. One notable difference is that synchronous file system operations are not available in Deno Deploy Subhosting.
Because the file system is read-only, all write operations fail with a
Deno.errors.PermissionDenied
error. This behavior can be emulated in Deno CLI
by specifying the --allow-read
permission flag, but denying all write
permissions.
While all of the file system functions available in the Deno CLI are available in Deno Deploy Subhosting, only these ones are really useful:
Deno.FsFile
: The Deno abstraction for reading and writing files.- The
readSync()
andwriteSync()
methods always throw on use. - The
write()
method always throws aDeno.errors.PermissionDenied
error.
- The
Deno.readDir
: Read a directory listing.Deno.readFile
: Read a file into memory.Deno.readTextFile
: Read a text file into memory as text.Deno.open
: Open a file handle for streaming reads.Deno.cwd
: Get the current working directory.Deno.stat
: Get the file info.Deno.lstat
: Get the file info without following symlinks.Deno.realPath
: Get the canonicalized path of a file.Deno.realPath
- Get the target path for the given symlink
Manifest
The virtual file system is backed by a manifest that describes the file tree of the virtual file system. This is the “fs manifest”. The manifest contains two pieces of information: the file tree, and the metadata for each file. The file contents are not part of the manifest and are retrieved separately.
The manifest has the following structure:
interface FSManifest {
/** The file system entries contained in this manifest, stored as a flat map.
*
* The keys of this map are the paths of the files in the manifest. The values
* are the metadata for each file. For each entry located within a parent
* directory, that parent directory must exist as an entry too. This also
* applies to the root directory.
*/
entries: Record<string, Entry>;
}
type Entry = EntryFile | EntryDirectory | EntrySymlink;
interface EntryFile {
kind: "file";
/** The size of the file in bytes. */
size: number;
/** The file hash (or other unique identifier) for the file. This is used as
* an identifier to retrieve file contents when the file is opened. */
hash: string;
}
interface EntryDirectory {
kind: "directory";
}
interface EntrySymlink {
kind: "symlink";
/** The target of the symlink. */
target: string;
}
To illustrate, an example manifest:
{
"entries": {
"": {
"kind": "directory"
},
"/hello.txt": {
"kind": "file",
"size": 5,
"hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
},
"/goodbye.txt": {
"kind": "file",
"size": 7,
"hash": "82e35a63ceba37e9646434c5dd412ea577147f1e4a41ccde1614253187e3dbf9"
},
"/foo": {
"kind": "directory"
},
"/foo/bar.txt": {
"kind": "file",
"size": 3,
"hash": "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"
},
"/bar": {
"kind": "symlink",
"target": "./foo"
}
}
}
Integration
To make use of the virtual file system feature, two origin RPC endpoints must be implemented by you. One endpoint is used to retrieve the fs manifest, while the other is used to fetch file contents for a given blob.
The GET /fs/manifest
origin RPC endpoint is
called with the deployment ID as a parameter. The manifest is cached for each
deployment, so not ever fs operation performed by a user will trigger this RPC
call.
The GET /fs/blob
origin RPC endpoint is called with
the hash of the file to be loaded. The origin should stream the response body to
minimize memory usage and caching. To support Deno.seek()
and similar
functions, the origin must support Range
headers for the /fs/blob
endpoint.
Blobs are cached, so multiple reads of the same file in an isolate will not
necessarily trigger multiple /fs/blob
RPC calls.
Limits
- A manifest must not contain more than 65,536 entries.
- Blob size must not exceed 4 GiB.
- Blob hashes must not exceed 512 bytes.
- Blob hashes must be globally unique per subhoster.
- File paths may not exceed 4096 bytes.
- Symlink targets may not exceed 4096 bytes.