Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.podflare.ai/llms.txt

Use this file to discover all available pages before exploring further.

What fork actually does

with Sandbox() as parent:
    parent.run_code("x = 42; import json")
    children = parent.fork(n=5)
    # Each child can access `x` and `json` immediately.
Conceptually, parent.fork(n=5) does this:
  1. Pause parent for a few milliseconds.
  2. Take a diff snapshot of parent’s memory — only dirty pages are captured.
  3. Resume parent immediately. The pause window is tiny.
  4. Prepare child memory from the shared base + the diff.
  5. Spawn N children in parallel. Each child gets a per-child rootfs clone (copy-on-write) and shares memory pages with its siblings until they diverge.

Timing

ntotal
1~90 ms
2~100 ms
5~100 ms
Spawn cost is nearly flat in N because children boot in parallel.

What each child inherits

From the parent’s moment of snapshot:
  • Python REPL state: variables, imported modules, open file handles, any in-memory objects.
  • Filesystem state: everything written to the parent’s rootfs so far.
  • Process tree: every running process in the VM. (Yes, including the Podflare agent + REPL.)
What children do not share after fork:
  • Subsequent writes to memory — isolated between siblings.
  • Subsequent writes to the rootfs — isolated between siblings.
  • Their control channel — each child is independently addressable by its own sandbox id.

Tree-search pattern

with Sandbox() as parent:
    parent.run_code("""
        import pandas as pd
        df = pd.read_csv('/data/medium.csv')
    """)

    # 5 different hypotheses
    plans = [
        "print(df['col_a'].mean())",
        "print(df['col_b'].mean())",
        "print(df[df.col_a > 0].shape)",
        "print(df.describe().loc['mean'])",
        "print(df.corr().iloc[0])",
    ]

    children = parent.fork(n=len(plans))
    try:
        results = [c.run_code(p) for c, p in zip(children, plans)]
        winner = children[pick_best_index(results)]
        parent.merge_into(winner)
    finally:
        for c in children:
            c.close()

diff(other)

Compare filesystem state between two sandboxes (typically two forks of the same parent):
a, b = parent.fork(n=2)
a.run_code("with open('/root/a.txt','w') as f: f.write('from a')")
b.run_code("with open('/root/b.txt','w') as f: f.write('from b')")

d = a.diff(b)
# { "added": ["/root/b.txt"], "removed": ["/root/a.txt"], "modified": [] }
Default compares /root and /tmp; pass paths=[...] to compare elsewhere. Implemented as two parallel sha256sum | sort invocations inside the two sandboxes, diffed SDK-side.

merge_into(winner)

Commit one fork’s state as the new state of the parent:
parent.merge_into(winner)
# parent.id is still valid; it now drives winner's VM.
# winner.close() becomes a no-op (marked defunct internally).
# Siblings you don't need: call close() explicitly.
Under the hood: the parent sandbox is destroyed and the winner takes over the parent’s id.

Limits

  • fork(n) with 1 <= n <= 32. Larger fanouts are deferred until we prove memory pressure at scale.
  • fork() requires a pool-warm parent. Sandboxes created with custom RAM or rootfs skip the pool and can’t be forked.