> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getnao.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Files and Storage

> Attach documents to a chat, query them with SQL, and save results to permanent storage

nao gives every user a durable folder the agent can read from and write to. It shows up to the agent as `/home`, part of the same file tree as the project context, and it is private to that user in that project.

Two things use it:

* **Attachments** - files you add to a message land in `/home/uploads`.
* **Saved results** - exports and intermediate results the agent writes, so they outlive the chat.

<Info>
  Permanent storage is configured once for the whole deployment with `NAO_STORAGE_BACKEND` (see [Configuring storage](#configuring-storage)). It defaults to `local`. When it is set to `none`, the agent has no write tool and file attachments are off - only [images](/nao-agent/chat/capabilities/overview#image-input) still work.
</Info>

## Attaching files

Add files the same way you add images: **Attach file** in the `+` menu of the chat input, drag and drop, or paste.

|                 |                                                                                                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **Documents**   | `csv`, `tsv`, `json`, `jsonl`, `parquet`, `xls`, `xlsx`, `pdf`, `docx`, `md`, `txt`, `html`, `xml`, `sql`, `yaml`, `yml` |
| **Images**      | `png`, `jpeg`, `gif`, `webp`                                                                                             |
| **Per message** | Up to 5 attachments, images and documents combined                                                                       |
| **Size**        | 5 MB per image; documents are capped by `NAO_STORAGE_MAX_FILE_SIZE_MB` (10 MB by default)                                |

Documents and images reach the model very differently. An image is inlined into the request so the model can look at it. A document is only ever handed over as a **path** in `/home/uploads` - never its contents - so a large spreadsheet costs nothing until the agent actually opens it.

## What the agent does with a file

* **`read`** extracts the text of a PDF page by page. On an `.xlsx` it returns the workbook outline instead of the cells - every sheet in tab order with its row and column counts - so the agent knows which sheet it wants before querying. Parquet and Word documents are not text, so `read` refuses them.
* **`search`** finds files by name, and **`grep`** looks inside them (on S3 backends, where files are not on a local disk, `grep` is unavailable and the agent falls back to `search` plus `read`).
* **`execute_sql`** queries tabular files in place - see below.
* **`execute_sandboxed_code`** mounts a `/home` path into the micro-VM through its `storage_files` argument, for anything the other tools cannot parse.

## Querying files with SQL

nao ships its own DuckDB engine alongside your warehouses, addressed as the database id **`duckdb_local`**. It is always available, and it is the only way to query a file or to join one against an earlier query result.

It can:

* read CSV, JSON, Parquet, and Excel files by their `/home` path,
* expose every earlier `execute_sql` result as a table named after its query id,
* join the two together - for example a spreadsheet someone uploaded against last quarter's revenue from the warehouse.

Just ask in plain English: *"join this CSV against our customers table and show me who is missing."*

<Note>
  `duckdb_local` is a reserved database id. A warehouse configured under that name in `nao_config.yaml` would be unreachable.
</Note>

## Saving results

The agent writes to `/home` when you ask it to keep, export, or update something.

* **`save_to` on `execute_sql`** writes a `duckdb_local` result straight to a file, as `csv` (for a file someone opens) or `parquet` (which keeps column types, so the result can be queried again later). The rows still come back in the chat as usual.
* **The `write` tool** saves anything else. `/home` is the only writable place in the tree; everything else is read-only.

When the agent mentions a stored file in its answer, clicking it opens the side panel viewer: spreadsheets render sheet by sheet, PDFs and markdown render inline, and text files are shown as-is. The **Download** button in the panel header saves the file to your machine.

## Your own storage

Open **Settings** -> **Storage** to see how much space your files take in the current project. You get your own space in every project you belong to, and nobody else can read it.

## Configuring storage

Storage is set through environment variables, not the UI. Admins can review the resolved configuration, a reachability check, and per-project usage under **Settings** -> **Storage**.

<Tabs>
  <Tab title="Local disk">
    ```bash theme={null}
    NAO_STORAGE_BACKEND=local
    NAO_STORAGE_LOCAL_PATH=./storage    # optional, defaults to ./storage
    ```

    The default. Point it at a directory on disk.

    <Warning>
      The path must be **durable**. In a container, mount a volume (or a PVC) at it - otherwise every restart wipes what users saved. Running more than one replica, every replica must mount the **same** read-write-many volume (NFS, EFS, Filestore, RWX PVC), or each replica sees a different set of files. Above one replica, prefer S3.
    </Warning>
  </Tab>

  <Tab title="S3">
    ```bash theme={null}
    NAO_STORAGE_BACKEND=s3
    NAO_STORAGE_S3_BUCKET=my-nao-storage
    NAO_STORAGE_S3_REGION=eu-west-1
    NAO_STORAGE_S3_PREFIX=nao                        # optional, share a bucket with other workloads
    NAO_STORAGE_S3_ENDPOINT=https://minio.internal:9000   # optional, for S3-compatible providers
    NAO_STORAGE_S3_FORCE_PATH_STYLE=true             # needed by MinIO
    NAO_STORAGE_S3_ACCESS_KEY_ID=                    # optional
    NAO_STORAGE_S3_SECRET_ACCESS_KEY=                # optional
    ```

    Works with AWS S3 and S3-compatible providers (MinIO, Cloudflare R2, ...). Recommended for any deployment above one replica.

    Credentials are optional: when omitted, the default AWS credential chain is used, so IAM roles, ECS task roles, and EKS/IRSA work with no configuration.
  </Tab>

  <Tab title="Off">
    ```bash theme={null}
    NAO_STORAGE_BACKEND=none
    ```

    The agent has no write tool and cannot reach stored files, and file attachments are disabled. Nothing already saved is deleted.
  </Tab>
</Tabs>

`NAO_STORAGE_MAX_FILE_SIZE_MB` (default `10`) caps the largest single file that can be written, on every backend. A bigger file is rejected before anything is stored.

## Next steps

<CardGroup cols={2}>
  <Card title="Tools, MCPs, Skills" icon="wand-magic-sparkles" href="/nao-agent/chat/capabilities/tools-mcps-skills">
    The full list of tools the agent can call
  </Card>

  <Card title="Deployment guide" icon="docker" href="/nao-agent/self-hosting/deployment-guide">
    Mount a durable volume when self-hosting
  </Card>
</CardGroup>
