Skip to main content
Most real workloads need data. This tutorial shows you how to get files into a sandbox, process them, and get results back out. You’ll learn three methods and when to use each one.

Method comparison

MethodDirectionBest forSize limit
copy_in() / copy_out()Host ↔ GuestFiles and directoriesLarge files
Volume mountsBoth (shared)Datasets, config filesNo limit
exec + base64EitherSmall inline data~1 MB (shell limit)

Prerequisites

pip install boxlite

Method 1: copy_in / copy_out

The most common approach. Upload a file, process it, download the results.
file_transfer.py
import asyncio
import boxlite


async def main():
    async with boxlite.SimpleBox(image="python:slim") as box:
        # Upload a script into the box
        # Note: destination must be a directory path, not a file path
        await box.exec("mkdir", "-p", "/workspace")
        await box.copy_in("/host/script.py", "/workspace/")

        # Run the script
        result = await box.exec("python", "/workspace/script.py")
        print(f"Exit code: {result.exit_code}")
        print(result.stdout)

        # Download the results
        await box.copy_out("/workspace/output.json", "/host/")


if __name__ == "__main__":
    asyncio.run(main())
When to use: Dynamic per-request files — scripts, input data, configuration that varies across runs.

Method 2: Volume mounts

Mount a host directory directly into the box. Files are shared in real time — no explicit copy step needed.
volume_mount.py
import asyncio
import boxlite


async def main():
    async with boxlite.SimpleBox(
        image="python:slim",
        volumes=[
            ("/host/datasets", "/mnt/data", True),      # Read-only input
            ("/host/results", "/mnt/results", False),    # Writable output
        ],
    ) as box:
        # Input data is already available at /mnt/data
        result = await box.exec(
            "python", "-c",
            "import os; print(os.listdir('/mnt/data'))"
        )
        print(result.stdout)

        # Write results — they appear on the host immediately
        await box.exec(
            "python", "-c",
            "open('/mnt/results/output.txt', 'w').write('done')"
        )


if __name__ == "__main__":
    asyncio.run(main())
When to use: Shared datasets or configuration that multiple boxes need access to. Use read-only mode for input data to prevent accidental modification.
Volume mounts give the guest direct access to host files. Always use read-only mode (True) for input data. Only use False for designated output directories.

Method 3: Inline data via base64

For small payloads (under ~1 MB), you can send data through a shell command without touching the filesystem.
inline_base64.py
import asyncio
import base64
import boxlite


async def main():
    async with boxlite.SimpleBox(image="python:slim") as box:
        # Encode a small script as base64
        data = b"print('hello from transferred script')"
        encoded = base64.b64encode(data).decode()

        # Send and execute in one command
        result = await box.exec(
            "sh", "-c",
            f"echo {encoded} | base64 -d > /tmp/script.py && python /tmp/script.py",
        )
        print(result.stdout)


if __name__ == "__main__":
    asyncio.run(main())
When to use: Trivially small payloads where you want to avoid the overhead of copy_in. Not suitable for binary files or anything over ~1 MB.

Putting it together

Here’s a realistic workflow: upload a CSV, run analysis code on it, and download the results.
full_workflow.py
import asyncio
import boxlite


async def main():
    async with boxlite.SimpleBox(
        image="python:slim",
        memory_mib=1024,
    ) as box:
        # 1. Create workspace directory
        await box.exec("mkdir", "-p", "/workspace")

        # 2. Upload the input data
        await box.copy_in("/host/sales_data.csv", "/workspace/")

        # 3. Upload the analysis script
        await box.copy_in("/host/analyze.py", "/workspace/")

        # 4. Run the analysis
        result = await box.exec("python", "/workspace/analyze.py")
        print(f"Analysis completed (exit code: {result.exit_code})")
        print(result.stdout)

        # 5. Download the results
        await box.copy_out("/workspace/report.json", "/host/")
        print("Results saved to /host/report.json")


if __name__ == "__main__":
    asyncio.run(main())
Use copy_in/copy_out for dynamic per-request files. Use volume mounts for shared datasets. Use inline base64 only for trivially small payloads.

What’s next?