Skip to content
This page View Markdown Open in ChatGPT Open in Claude

Sandbox settings

The code of an account runs in sandboxes : Docker containers of the account, one kind per language. 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
Where code runs : sandboxes per account and language, and the native process API Maker one process per server, every core ; settings and schemas run here a run past its time is cut short, an error ends it sandboxes : Docker containers of each account account shop · TypeScript 1 sandbox, more while busy, up to the count account shop · Python its own runtime, packages and Dockerfile account crm · Go native process · runOnNativeProcess on the machine, beside API Maker : not isolated The trust model Containers run privileged, with no memory limit : a guard against faulty code, not hostile code. Separate clients : separate servers. Like the sandboxes, the native runner answers what the code asks of g.sys itself, and hands only the answer back.

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 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, 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 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. 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 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
1
2
3
4
5
6
7
8
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.
  • Kotlin : ENV AM_KOTLIN_VERSION=2.3.0 above {{AM_PACKAGES}} names 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 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 (13000 ms)
the hooks of the APIs of instances, databases, tables and system APIs the time of the request sandboxReqTimeout
an event listener eventListenerTimeoutInMinutes sandboxReqTimeout
a scheduler schedulerTimeoutInMinutes 10 minutes
a migration script dbMigrationTimeoutInMinutes 10 minutes
a process initializer, in each runner it runs in processInitializerTimeoutInMinutes sandboxReqTimeout
  • A request names a time of its own with the header 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.