> For the complete documentation index, see [llms.txt](https://dev.ubidots.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dev.ubidots.com/ubifunctions/storage/mutiple-files.md).

# Multiple files

## Overview

Supporting multiple files in UbiFunctions improves flexibility and scalability. When building serverless functions, splitting code into multiple files improves maintainability, enables reuse, and aligns with common software development practices.

UbiFunctions allows you to use multiple files such as:

* **Source files:** These files contain code that can be executed.
* **Config files:** These are typically `.json`, `.conf`, `.toml`, or similar files. They do not contain executable code. Instead, they provide the data and parameters your logic needs to run with a particular behavior.
* **Data files:** These are files that store information in various formats, such as `.csv`, `.txt`, or `.json`. They can contain structured, semi-structured, or unstructured data used as input for processing or analysis.
* **Binary files:** These are non-text files, such as machine learning models (`.tflite`, `.onnx`), documents (`.pdf`, `.xlsx`), images, or databases (`.sqlite`). See [Binary files](#binary-files).

## Creating a file

To create a file in your UbiFunction root directory, click the **+** icon in the files pane, then select **New file**. Enter a name. The new file is added to your UbiFunction:

| <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FwnEJMlxxHmiNbY7aC2Gv%2Fimage.png?alt=media&amp;token=6bc9732a-8357-43ac-b3f5-f375c5722b3b" alt="" data-size="original"> | <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FNbob4zygxUCMThrXnI1j%2Fimage.png?alt=media&amp;token=c587cdff-d577-4c33-af5b-5ed05211c3f9" alt="" data-size="original"> |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

## Creating a folder

Folders help you organize modules more effectively. To create a folder, click the **+** icon in the files pane, then select **New folder**. Enter a name. The new folder is added to your UbiFunction:

| <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FLlXctUMHAvbL1DAHHEit%2Fimage.png?alt=media&amp;token=6d142d6b-2c0b-4517-9ad6-c17b37ab4893" alt="" data-size="original"> | <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FsJLH4qjD8puxSI8Iy9d8%2Fimage.png?alt=media&amp;token=bf549b14-aad4-4487-829e-f2732250400e" alt="" data-size="original"> |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

### Creating files or folders within a folder

To create a file or folder inside an existing folder, hover over the folder, click the three-dot menu, and select **New file** or **New folder**.

| <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FLIyymL16uKQ73EV3c7SN%2Fimage.png?alt=media&amp;token=ec3e4173-a21a-4a0c-9c1f-1c4309a7cfb4" alt="" data-size="original"> | <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FehhYyNfCyyumSNP8mL2l%2Fimage.png?alt=media&amp;token=f325e045-8ce6-4bfc-b606-b8631d4f6060" alt="" data-size="original"> |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

## File structure and imports

When you add files or folders to a UbiFunction, they behave like a directory on your local machine, with the root directory as the working directory. For example, if you add `decoder.py|js` alongside the main script, you can import it like this:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const decoder = require('./decoder');
```

{% endtab %}

{% tab title="Python" %}

```python
import decoder
```

{% endtab %}
{% endtabs %}

Similarly, if you create a folder `utils` and add a file `parser.py` or `parser.js` inside it, the structure behaves like a subdirectory on your computer. To import from it, use:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const parser = require('./utils/parser');
```

{% endtab %}

{% tab title="Python" %}

```python
from utils import parser
```

{% endtab %}
{% endtabs %}

This means you can treat the UbiFunction file structure like a local project folder.

{% hint style="info" %}
UbiFunctions use a protected file system. You can create files and folders through the UI, but scripts run in a strictly read-only environment and cannot write files or create new files and folders.
{% endhint %}

## Data and config files

UbiFunctions let you include data and configuration files, such as `.json`, `.conf`, `.txt`, and `.csv`, to provide inputs or settings for your functions. To read a file, handle it the same way you would in a local script:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const fs = require('fs');

// Read a JSON file
// Adjust the file's path accordingly
const settings = JSON.parse(fs.readFileSync('settings.json', 'utf-8'));
```

{% endtab %}

{% tab title="Python" %}

```python
import json

# Read a JSON file
# Adjust the file's path accordingly
with open('settings.json', 'r') as file:
    settings = json.load(file)
print(settings)
```

{% endtab %}
{% endtabs %}

## Uploading files

To upload a file from your computer, click the **+** icon in the files pane, then select **Upload file**. To upload it into a folder, hover over the folder, click the three-dot menu, and select **Upload file**.

## Binary files

You can upload binary files and read them from your code. For example, you can bundle a trained model and run it with the [ML Inference runtime](/ubifunctions/runtimes/python.md#ml-inference). The file reaches your function exactly as you uploaded it.

The following binary file types are supported:

| Category                | Types                                                                                                             |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Machine learning models | `.tflite`, `.onnx`, `.pb`, `.pt`, `.pth`, `.h5`, `.hdf5`, `.gguf`, `.ggml`, `.safetensors`                        |
| Data                    | `.parquet`, `.feather`, `.arrow`, `.sqlite`, `.db`, `.bin`, `.dat`                                                |
| Documents               | PDF, Word, Excel, and PowerPoint files                                                                            |
| Media                   | Images (PNG, JPEG, GIF, WebP, BMP, TIFF, AVIF, ICO), audio (MP3, WAV, OGG, FLAC), and video (MP4, AVI, MKV, WebM) |
| Other                   | Fonts (TTF, OTF, WOFF, WOFF2), WebAssembly (`.wasm`), and archives (`.zip`, `.gz`, `.bz2`)                        |

For security reasons, the following file types are blocked:

* Pickle and NumPy files: `.pkl`, `.pickle`, `.npy`, `.npz`. Loading these files can run arbitrary code. Export your model to ONNX instead. See [Models trained in other frameworks](/ubifunctions/runtimes/python.md#models-trained-in-other-frameworks).
* Executables and native libraries, such as `.exe`, `.dll`, `.so`, `.dylib`, `.jar`, `.msi`, `.deb`, and `.rpm`.
* Shell and system scripts, such as `.sh`, `.bash`, `.zsh`, `.bat`, `.cmd`, `.ps1`, and `.vbs`.

Binary files with other extensions are rejected. Each file can be up to 5 MB. See [Specs and Limits](/ubifunctions/specs-and-limits.md) for the limit on the function's total size.

To read a binary file, open it in binary mode:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const fs = require('fs');

// Returns a Buffer with the file's bytes
const model = fs.readFileSync('model.onnx');
```

{% endtab %}

{% tab title="Python" %}

```python
with open('model.onnx', 'rb') as file:
    model = file.read()
```

{% endtab %}
{% endtabs %}

## Example

Suppose you have several device types on an LNS sending data continuously. For each uplink, you need to decode the payload and forward it to the corresponding device in Ubidots.

You can solve this with a UbiFunction that uses separate scripts for each device type and calls them from the main function.

For this example, create:

* A folder called *modules*. Inside it, create:
  * A Python script called *s2100.py*. This is the decoder for the s2100 device.
  * A Python script called *s210x.py*. This is the decoder for the s210x device.
  * A Python script called *utils.py*. This file contains shared utility functions.
* A configuration file called *device\_config.json* that stores the configuration for each device type.

It should look like this:\ <img src="https://884329393-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MhzNRg0B4ECiNXc093G%2Fuploads%2FCqRttZqk92KAgp4qxuUW%2Fimage.png?alt=media&amp;token=8825d2e9-139d-4481-8ce7-7155341bc06e" alt="" data-size="original">

The following are the contents of each script:

**s2100.py script**

```python
def s2100_decode(data: int) -> dict:
    """Decode data for s2100 device."""
    temperature = (data & 0x3) >> 0
    humidity = (data & (0x3 << 2)) >> 2
    battery = (data & (0x3 << 4)) >> 4

    return {
        "temperature": temperature,
        "humidity": humidity,
        "battery": battery
    }
```

#### s210x.py script <a href="#h_bc270579ec" id="h_bc270579ec"></a>

```python
def s210x_decode(data: int) -> dict:
    """Decode data for s210x device."""
    soil_electrical_conductivity = (data & 0x3) >> 0
    battery = (data & (0x3 << 2)) >> 2

    return {
        "soil_electrical_conductivity": soil_electrical_conductivity,
        "battery": battery
    }
```

#### utils.py script <a href="#h_e0291278e3" id="h_e0291278e3"></a>

```python
def parse_data(data_str: str) -> int:
    """Convert a binary string to an integer."""
    return int(data_str, 2)

```

\
**device\_config.json**

```python
{
    "s2100" : {"color" : "#fefefe"},
    "s210x" : {"color" : "#ffffff"}
}
```

#### main.py <a href="#h_b306192085" id="h_b306192085"></a>

```python
import requests
import time
import json
import os
from modules.utils import parse_data
from modules.s2100 import s2100_decode
from modules.s210x import s210x_decode

decoders = {
    "s210x" : s2100_decode,
    "s2100" : s210x_decode
}

def main(args):

    """Decode payload based on device type."""
    device_type = args.get("device")
    data_str = args.get("data")
    
    if not device_type or device_type not in decoders:
        print(f"Device type: {device_type} not supported...")
        return {"status" : "error"}

    # Convert binary string to integer
    data = parse_data(data_str)
    decoded_data = decoders[device_type](data)

    # Open and read the JSON file
    with open("device_config.json", 'r') as file:
        config = json.load(file)

    print(config[device_type])
    print(decoded_data)
    return {"status" : "success" , "data" : decoded_data}
```

If you execute this UbiFunction with the following test payload:

```python
{"device": "s2100", "data": "0b01011010"}
```

It should output something like this:

```python
{'color': '#fefefe'}
{'soil_electrical_conductivity': 2, 'battery': 2}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://dev.ubidots.com/ubifunctions/storage/mutiple-files.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
