---
question: How does a module write files that Files can show?
kind: task
via_web: na
via_cli: na
via_python: available
via_api: available
via_config: na
ref_python: ObjectStorageService
ref_api: GET /api/files/raw/{path}
prereq: For the Python steps, an in-engine module listed under `modules:` in `config.yaml`. [Create a module](/user-guide/build/modules/creating-a-module) first.
next:
  - /capabilities/build/files/upload-a-file
  - /capabilities/build/modules/module-jobs
---

# Use files in code

Nexus Files and modules share one object storage service. A module reads what members upload, and members see what a module writes into their drive. Code outside the engine uses the Files API instead.

## Web UI

Not applicable. People use Files in Nexus: see [Upload a file](/user-guide/build/files/upload-a-file?via=web). Super admins can check what a module wrote in System › Data › Object storage.

## CLI

Not applicable. There is no `abi` command for object storage. Use another tab on this page. The command list is the [CLI reference](/user-guide/reference/cli).

## Python

### Declare the service

```python title="src/my_module/__init__.py"
from naas_abi_core.module.Module import BaseModule, ModuleDependencies
from naas_abi_core.services.object_storage.ObjectStorageService import ObjectStorageService


class ABIModule(BaseModule):
    dependencies: ModuleDependencies = ModuleDependencies(
        modules=[],
        services=[ObjectStorageService],
    )
```

### Read and write

```python
storage = self.engine.services.object_storage
storage.put_object("my_module", "notes/a.txt", b"hello")
content = storage.get_object("my_module", "notes/a.txt")   # bytes
names = storage.list_objects("my_module/notes")             # ["my_module/notes/a.txt"]
storage.delete_object("my_module", "notes/a.txt")
```

`put_object` replaces an existing object. `get_object` and `delete_object` raise `Exceptions.ObjectNotFound` (from `ObjectStoragePort`) for a missing key, and `list_objects` for a missing prefix. `list_objects` returns the direct children as full paths, `.nexus_folder` markers included; `list_objects_recursive` walks the whole prefix. `get_object_stream` and `put_object_stream` handle large files.

### Use a workspace drive

To read what members uploaded, or to put a file where they will see it, use the drive's prefix:

```python
prefix = f"naas_abi/workspace-drive/{workspace_id}/reports"
storage.put_object(prefix, "summary.md", b"# Summary\n")
```

A prefix of the module's own, like `my_module`, is not in any drive: Files does not show it. Marketplace modules take a `datastore_path` setting for that prefix.

:::warning
Do not write to the local disk and expect Files to show it. With the `s3` adapter, the bytes are not on the disk at all.
:::

## REST API

From code outside the engine, the Files routes of the Nexus API. Auth: a Nexus session of a workspace member (`POST /api/auth/login` returns the access token).

### List a folder

```bash
curl "http://localhost:9879/api/files/?path=reports&workspace_id=$WORKSPACE_ID&scope=workspace" \
  -H "Authorization: Bearer $NEXUS_TOKEN"
```

The answer is `{files, path, total}`. `limit`, `offset`, `search` and `sort_by` (`name`, `size`, `modified`) page and filter it.

### Read a file

```http
GET /api/files/raw/reports/summary.md?workspace_id={workspace_id}&scope=workspace
```

`raw` returns the bytes. `GET /api/files/{path}` returns a text file as JSON, and `PUT /api/files/{path}` replaces a text file's content.

## Config

Not applicable. `services.object_storage` picks the store, and the code is the same for every adapter. See [Object Storage](/user-guide/get-started/configuration#object-storage).
