Welcome to the new Golem Cloud Docs! 👋
Common Guides
Worker Filesytem

Worker Filesystem

Each worker runs in a sandboxed filesystem. Both the / path and the current working directory of a worker point to the root of this sandboxed filesystem. There is no way for a worker to access files outside its own filesystem.

To interact with the worker filesytem, you normally just need to use your regular filesystem apis. The language specific tooling will take care of translating these to invocations of the wasi:filesystem (opens in a new tab) api which is implemented by Golem.

Example

This section assumes that you have a Golem project with an app manifest. If you don't have one yet, please follow the guide and then continue here.

This example will walk you through creating a worker that will interact with its sandboxed filesystem.

Defining the component

We begin by adding a new component to our application:

golem component new rust example:filesystem

Adjust the wit file defining the component so we have a convenient entrypoint. This will just be used to invoke the component, so feel free to name the functions as you like.

diff --git a/components-rust/example-filesystem/wit/example-filesystem.wit b/components-rust/example-filesystem/wit/example-filesystem.wit
index 65b5dda..e56b6e8 100644
--- a/components-rust/example-filesystem/wit/example-filesystem.wit
+++ b/components-rust/example-filesystem/wit/example-filesystem.wit
@@ -3,8 +3,7 @@ package example:filesystem;
 // See https://component-model.bytecodealliance.org/design/wit.html for more details about the WIT syntax
 
 interface example-filesystem-api {
-  add: func(value: u64);
-  get: func() -> u64;
+  run: func();
+  get-contents: func() -> string;
 }
 
 world example-filesystem {

Finally we need to adjust the implementation of the component to write a file when invoked:

mod bindings;
 
use crate::bindings::exports::example::filesystem_exports::example_filesystem_api::Guest;
 
struct Component;
 
impl Guest for Component {
    fn run() {
        std::fs::write("/foobar.txt", "Hello, World!").unwrap()
    }
    fn get_contents() -> String {
        std::fs::read_to_string("/foobar.txt").unwrap()
    }
}
 
bindings::export!(Component with_types_in bindings);

Invoking the worker

Once we have defined the component, we can the deploy the component and invoke a worker using the Golem cli:

golem app deploy example:filesystem
golem worker invoke example:filesystem/test-worker 'example:filesystem-exports/example-filesystem-api.{run}()'

As part of the invocation, the worker performed the side effect of writing a file in its sandboxed filesystem. This file will persist and can be used in all future invocations. For example:

golem worker invoke example:filesystem/test-worker 'example:filesystem-exports/example-filesystem-api.{get-contents}()'
Invocation results in WAVE format:
  - "Hello, World!"

Initial File System

This section builds on the project and Golem state created in the example project.

The Initial File System (IFS) refers to all files that are present in the worker filesystem before the worker is started. These can include configuration files, static assets and other things that you want to include with your worker.

The IFS is configured on the level of a component, meaning that all workers created from a given component + version will always start with the same filesystem. To configure the IFS, include a files section in your golem.yaml

⚠️

If you are using profiles in your golem.yaml, you currently have to include the files section in each of your profiles when overriding.

components:
  example:filesystem:
    template: rust
    profiles:
      debug:
        files:
        - sourcePath: ./files/foo.txt
          targetPath: /foobar.txt
          permissions: read-write
        - sourcePath: ./files/bar.txt
          targetPath: /bar.txt
          permissions: read-only
      release:
        files:
        - sourcePath: ./files/foo.txt
          targetPath: /foobar.txt
          permissions: read-write
        - sourcePath: ./files/bar.txt
          targetPath: /bar.txt
          permissions: read-only

After deploying the component, any new workers created will have the file /foobar.txt (and ./foobar.txt as the worker is starting the root) available to them. The file /bar.txt on the other hand is only available for reading. Trying to open the file for writing will fail with a language-dependent error.

echo "I'm already here" > ./files/foobar.txt
golem app deploy example:filesystem
golem worker invoke example:filesystem/test-worker-2 'example:filesystem-exports/example-filesystem-api.{get-contents}()'
Invocation results in WAVE format:
  - "I\'m already here\n"

Updating a worker

Updating a worker that uses IFS requires some special consideration depending on the update mode you choose:

  • Automatic updates: When using automatic updates the old worker invocations are replayed on top of the new IFS. This means that the worker should produce exactly the same results and side effects as it did with the old IFS. For example, changing the format of a file will work without issues, but changing a file that gets read by the worker and returned to the user will likely lead to divergence. In such cases a manual update might be necessary.
  • Manual updates: When using manual updates, you are responsible for saving and restoring the content of files in the worker filesystem. You can use the golem:api/save-snapshot function to persist the files and later restore / migrate them using golem:api/load-snapshot.

Externally accessing worker files

You can use file-server worker bindings to automatically deploy a REST API that allows accessing the files on a worker filesystem.