# Sandbox Settings

> Where the code of an API Maker account runs - the runtime and version of each language, its packages from npm, PyPI, Packagist, NuGet, Go modules, crates.io and Maven Central, your own Dockerfile, the images on every server, the sandbox count, the automatic restart and the allowed origins.

Source: https://docs.apimaker.dev/v4/docs/settings/sandboxSettings.html

The code of an account runs in sandboxes : Docker containers of the account, one kind per [language](https://docs.apimaker.dev/v4/docs/languages/index.html). This page says what each one is made of. Page : `Operations → Sandbox Settings`.

| | |
|---|---|
| Languages | TypeScript / JavaScript, Python, PHP, C#, Go, Rust, Java, Kotlin : each with its own runtime, version, packages and Dockerfile |
| Images | built in the background on every server when you save, shared by every account with the same settings |
| Sandbox count | the most sandboxes of one language at a time, on each server |
| Restart every | sandboxes start anew after this many seconds, without dropping a request |
| Allowed origins | the web origins allowed to call the APIs from a browser |

> Diagram : Where code runs : sandboxes per account and language, and the native process
>
> One API Maker process per server hands the code of each account to the sandboxes of that account : Docker containers, one kind per language, more of them while they are busy, up to the sandbox count. Code marked runOnNativeProcess runs on the machine instead, beside API Maker. The containers run privileged and without a memory limit : they guard against faulty code, not against hostile code.

> **Warning : A guard against faulty code, not hostile code**
>
> The containers run privileged and without a memory limit : they keep API Maker running when code fails, but code which wants to can reach the server, and the secrets of the other accounts on it. Run only code you trust, and use separate servers for clients who must not see each other's data. See [the sandboxes](https://docs.apimaker.dev/v4/docs/security/overview.html#sandboxes) in the security overview.

## Languages

The list on the left has one row per language, with the image its sandboxes are built from and a dot for the state of that image : green ready, amber building, red failed, grey not built yet. Select a language to edit it.

### Runtime and version

- **TypeScript / JavaScript** runs on **Node.js** or **Bun**. The code does not change with the runtime.
- **Each runtime has its own settings** : click a runtime to edit its version and its Dockerfile. The packages are the ones of the language, shared by its runtimes.
- **Use by default** : the runtime marked with a star runs every piece of code which names no runtime. Code can [name its runtime itself](https://docs.apimaker.dev/v4/docs/languages/index.html#choosing), so one API runs on Node.js and another on Bun in the same account ; each runtime in use gets an image of its own.
- **Settings use no sandbox** : the Basic Info of a custom API, the settings of APIs, schemas, the texts of internationalization and secrets are TypeScript which [API Maker runs itself](https://docs.apimaker.dev/v4/docs/languages/index.html#settings-run) when you save them. They need no runtime, no image and no packages : an account which runs its code on Bun has no image of Node.js for them.
- A runtime no code names and you never opened uses its default version : nothing has to be set for it.
- The **version** is picked from a list : the released versions of the official image which API Maker runs, newest first (`24` or `22.20.0` for Node.js, `3.13` for Python, `8.4` for PHP). The list is read from Docker Hub (C# : from the registry of Microsoft) and has a search field when it is long. Clear the choice for the default version.
- API Maker runs the versions released after January 2023 : see [the oldest version of each runtime](https://docs.apimaker.dev/v4/docs/languages/index.html#versions). An older version is not in the list, and is refused when the settings are saved : `Python 3.10 is too old : API Maker runs Python 3.12 and later.` A version saved before, which is not offered any more, is shown as *not offered* until you pick another one.
- **PHP** : only its released versions are offered (`8.4`, `8.4.12`, no release candidate). The runner of PHP loads API Maker with the FFI extension, which the official images are built without : the image of the sandboxes gets it when it is built, and the build fails rather than give a sandbox without it.
- **Java and Kotlin** : the version is the one of the JDK (`25`, `21`). Kotlin runs on the JDK too, in an image of its own which gets [the compiler of Kotlin](https://docs.apimaker.dev/v4/docs/languages/kotlin.html#the-compiler) when it is built.
- The image the version gives is shown next to it. Without a version : `node:24-slim`, `oven/bun:1-slim`, `python:3.13-slim`, `php:8.4-cli`, `mcr.microsoft.com/dotnet/sdk:10.0`, `golang:1.27`, `rust:1-slim`, `eclipse-temurin:25-jdk` (Java and Kotlin).

### Packages

Nothing is installed unless you add it. Search the registry of the language, pick a package and a version, and **Add**. The version is one of the list or one you type (a range as `^4.17.0`) ; empty is the latest. A package can be switched off without removing it.

| Language | Registry | Name | Version |
|---|---|---|---|
| TypeScript | npm | `lodash`, `@types/node` | `4.17.21`, `^4.17.0`, `latest` |
| Python | PyPI | `requests`, `uvicorn[standard]` | `2.32.3`, `>=2,<3`, `~=2.32` |
| PHP | Packagist | `guzzlehttp/guzzle` | `7.9.2`, `^7.9` |
| C# | NuGet | `Newtonsoft.Json` | `13.0.3`, `13.*`, `[1.0,2.0)` |
| Go | Go modules | `github.com/google/uuid` | `v1.6.0`, `1.6.0`, `latest` |
| Rust | crates.io | `serde[derive]`, `tokio[rt-multi-thread,macros]` | `1`, `^1.40` |
| Java | Maven Central | `com.google.code.gson:gson` (`group:artifact`) | `2.11.0`, `33.4.0-jre`, `[1.0,2.0)` |
| Kotlin | Maven Central | `org.jetbrains.kotlinx:kotlinx-coroutines-core` | `1.10.2`, `[1.9,2.0)` |

- PyPI and Go modules have no search : type the exact name, the versions come from the registry.
- Maven Central is searched by words (`gson`), or by the whole name of a package (`com.google.code.gson:gson`). Java and Kotlin each have a list of their own.
- A name or a version which can not be one is refused when you save, in words : `'requests; rm' is no name of a package of the Python Package Index…`.
- While code runs nothing is downloaded : a package which is not in the list is not there.

### Dockerfile

Every language has a default Dockerfile. Switch **Customize** on to write your own : it is one file with three markers API Maker fills in.

**A Dockerfile of Python with a system library**

```dockerfile
FROM {{AM_BASE_IMAGE}}

# What your code needs from the system : built once, above the packages.
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/*

{{AM_PACKAGES}}

{{AM_RUNNER}}
```

| Marker | Becomes |
|---|---|
| `{{AM_BASE_IMAGE}}` | the image of the runtime in the version of the settings |
| `{{AM_PACKAGES}}` | the tools of the registry, the folder the code runs in and your packages. PHP : the FFI extension first |
| `{{AM_RUNNER}}` | the program of the sandbox, the runner of the language, and what starts them |

- Order matters for the time of a build : the lines above `{{AM_PACKAGES}}` are built once, a change of packages does not install the system again, and the runner comes last.
- Without `{{AM_PACKAGES}}` the packages come right before the runner; without `{{AM_RUNNER}}` the runner comes at the end.
- `ENTRYPOINT` and `CMD` are API Maker's; a marker in a comment is no marker; a marker written twice is refused.
- A variable the code reads (`process.env.TZ`, `os.environ['TZ']`, `getenv('TZ')`, `System.getenv("TZ")`) is an `ENV` line : `ENV TZ=UTC` above `{{AM_PACKAGES}}`. It is part of the image : keep secrets in [Secrets](https://docs.apimaker.dev/v4/docs/secrets/secrets.html).
- Kotlin : `ENV AM_KOTLIN_VERSION=2.3.0` above `{{AM_PACKAGES}}` names [the compiler](https://docs.apimaker.dev/v4/docs/languages/kotlin.html#the-compiler) the image gets.
- PHP : a Dockerfile which starts from another image than `{{AM_BASE_IMAGE}}` needs the FFI extension, or the tools which install it (`docker-php-ext-install`, as the official images have) : without the extension the image is not built, and the log of the build says why.
- **Final Dockerfile** shows the file as it is built, with the markers filled in and the steps API Maker adds for its own library. **Reset to default** brings the default back.

### Images and sandboxes

The state of the image of the language on every server : building (since when), ready (when, or *was there already* when another account built the same image), failed (the error, and **Log** for the end of the build). Below it, the sandboxes which run on the server the page asked : their port, runners, the requests running, how long they have been up and idle.

- **Saving** builds the images which changed, on every server, in the background. The sandboxes of the account start anew with the new image; requests which were running finish on the old one.
- **⟳** in the title of the language starts its sandboxes anew on every server, with the same image.
- An image is named after what it is made of : two accounts with the same runtime, version, packages and Dockerfile share one image. Images no account uses any more are removed every hour.

## Sandbox count

The most sandboxes one language of the account has at a time, on each server (1 to 5). By default one sandbox runs on a server, for the whole API Maker process : a sandbox does not belong to a thread, every thread hands its code to the same one. The first request starts it; while it is busy, another starts in the background, up to this count. Each sandbox also opens more runners of its own while all of them are busy, up to as many as the server has cores. 1 or 2 per CPU core of the server is plenty.

A [separate sandbox](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html#separate-sandbox) of custom APIs has its own count.

## Time of a run

Every runner gives each piece of code it is handed the time of the item the code belongs to : the first runner of a sandbox, each runner a busy sandbox opens, and the runner of the server which runs the code marked `runOnNativeProcess`. Code which needs nothing of a sandbox runs in the server itself, and is given the same time. When the time is over, the request ends with the error `API didn't respond in <ms>ms.`, and the runner which holds the code is set aside : it takes no more requests, and is ended once the other requests it runs are over, each in its own time. Only the code which did not end in time is cut short : a request which runs beside it on the same runner ends as it would have, or when its own time is over. The other runners of the sandbox go on, and the next code marked `runOnNativeProcess` meets a new runner of the server. The time a sandbox or a runner takes to start is not counted.

| Code of | Its time | When it names none |
|---|---|---|
| a custom API, and the hooks of its versions | `customApiTimeoutInSeconds`, in seconds | `sandboxReqTimeout` of the [configuration](https://docs.apimaker.dev/v4/docs/am-resources/api-maker-configurations.html) (`13000` ms) |
| the hooks of the APIs of instances, databases, tables and system APIs | the time of the request | `sandboxReqTimeout` |
| an [event listener](https://docs.apimaker.dev/v4/docs/apis-all/events/user-created-events-api.html) | `eventListenerTimeoutInMinutes` | `sandboxReqTimeout` |
| a [scheduler](https://docs.apimaker.dev/v4/docs/apis-all/schedulers/user-created-schedulers-api.html) | `schedulerTimeoutInMinutes` | 10 minutes |
| a [migration script](https://docs.apimaker.dev/v4/docs/features/database-migration.html) | `dbMigrationTimeoutInMinutes` | 10 minutes |
| a [process initializer](https://docs.apimaker.dev/v4/docs/features/process-initializers.html), in each runner it runs in | `processInitializerTimeoutInMinutes` | `sandboxReqTimeout` |

- A request names a time of its own with the header [`x-am-sandbox-timeout`](https://docs.apimaker.dev/v4/docs/apis-all/header/requestHeader.html#x-am-sandbox-timeout) : it wins over `customApiTimeoutInSeconds`.
- The API testing page tries a scheduler, a migration script or a process initializer with the time it runs with.
- A runner whose process initializer did not end in time stops waiting for it and takes requests.
- A sandbox whose last runner was set aside takes no more requests : the next request starts a new one, and the old one goes once its requests are over.

## Restart every

Sandboxes start anew after this many seconds, one after the other : a new one starts first and takes the requests, the old one finishes what it runs. Use it for code which holds memory it does not give back. Empty : never.

## Allowed origins

With one origin listed, a browser request from any other origin is refused with `403` before anything runs. Add the origins of your web apps. Empty : every origin.

## What is saved

The settings are part of the admin user (`settings.sandbox.environments`, `sandboxCountOverrideAdmin`, `automaticSandboxRestartInSeconds`, `allowedOrigins`), so they have a history (the git button of the page) and travel with the project through [git](https://docs.apimaker.dev/v4/docs/Git/git.html).

## Related

- [Languages and runtimes](https://docs.apimaker.dev/v4/docs/languages/index.html) · [Custom API settings](https://docs.apimaker.dev/v4/docs/settings/customApiSettings.html) · [Process initializers](https://docs.apimaker.dev/v4/docs/features/process-initializers.html) · [Security features](https://docs.apimaker.dev/v4/docs/features/security-features.html#allowed-origins)
