Skip to main content
Persistence is useful when one execution depends on artifacts created by a previous execution. If you do not need cross-run state, prefer ephemeral mode for isolation and simplicity.
On remote execution, persistence is controlled by sessionId. Without sessionId, requests run as ephemeral executions.

Ephemeral vs persistent

ModeState between runsPerformance profileBest for
ephemeralnone< 150ms (warm pool)isolated one-off tasks
persistentyes~300ms (cold), ~120ms (warm)multi-step workflows
Ephemeral mode performance depends on your poolStrategy. The default fast strategy uses a background cleanup loop to ensure instant availability.

What persists in persistent mode

Inside the same container, subsequent runs can reuse:
  • files under /sandbox
  • installed dependencies from previous operations
  • runtime artifacts generated during prior executions
Persistent containers are runtime-bound. Use one session/engine per runtime.

CLI usage

isol8 run \
  --persistent \
  -e "x = 10" \
  --runtime python

isol8 run \
  --persistent \
  -e "print(x + 5)" \
  --runtime python
--persist is separate from --persistent:
  • --persistent: reuse container across runs.
  • --persist: keep container alive after completion for manual inspection.

Library usage

const isol8 = new DockerIsol8({ mode: "persistent" });
await isol8.start();

await isol8.execute({ code: "x = 40", runtime: "python" });
await isol8.execute({ code: "print(x + 2)", runtime: "python" });

await isol8.stop();

API session usage

Use sessionId with POST /execute.
{
  "sessionId": "session-123",
  "request": {
    "code": "x = 123",
    "runtime": "python"
  }
}
Reuse same sessionId for follow-up calls, then delete explicitly:
curl -X DELETE http://localhost:3000/session/session-123 \
  -H "Authorization: Bearer $ISOL8_API_KEY"
RemoteIsol8.stop() also deletes the remote session when sessionId is configured.

File movement patterns

Inject files before execution

await isol8.execute({
  code: 'print(open("/sandbox/data.txt").read())',
  runtime: "python",
  files: {
    "/sandbox/data.txt": "hello",
  },
});

Retrieve files after execution

const result = await isol8.execute({
  code: 'open("/sandbox/out.txt", "w").write("done")',
  runtime: "python",
  outputPaths: ["/sandbox/out.txt"],
});

Direct file API in active session

  • POST /file upload base64 content
  • GET /file download base64 content
File APIs require an active persistent context. In remote mode, putFile/getFile throw if sessionId is missing.

Session lifecycle and pruning

Server-side session cleanup is controlled by:
  • cleanup.autoPrune
  • cleanup.maxContainerAgeMs
If idle sessions are being removed earlier than expected, increase maxContainerAgeMs or disable auto-pruning.

Choosing the right mode

Choose ephemeral when:
  • workloads are independent
  • isolation between requests is a priority
  • you need predictable clean-state semantics
Choose persistent when:
  • workflows are iterative/multi-step
  • file reuse is central to task flow
  • setup cost should be amortized across related runs

FAQ

--persistent enables state reuse across runs. --persist keeps the container alive after execution for inspection/debugging.
No. A persistent container is runtime-bound. Create a new session/engine for a different runtime.
Call DELETE /session/{id} directly, or use RemoteIsol8.stop() when your client was created with sessionId.

Troubleshooting quick checks

  • State not retained between runs: ensure --persistent (CLI) or sessionId (API/RemoteIsol8) is set.
  • File operations require a sessionId: create RemoteIsol8 with sessionId before putFile/getFile.
  • Session disappears unexpectedly: check cleanup.autoPrune and cleanup.maxContainerAgeMs in config.
  • Runtime switch error in persistent mode: use separate sessions per runtime.