Skip to main content
Templates define the runtime environment for your sandboxes. Build custom templates with the TemplateBuilder for full control over your execution environment — install packages, configure runtimes, set resource limits, and more.

Building Templates

Build custom templates using TemplateBuilder to create environments tailored to your specific needs. Templates support multiple source types: Docker images, local directories, Git repositories, and raw Dockerfiles.

From a Docker Image

The most common approach — start from any Docker image and add your dependencies and application code.
from gravixlayer import GravixLayer, TemplateBuilder

client = GravixLayer(api_key="YOUR_API_KEY")

app_code = """\
from fastapi import FastAPI

app = FastAPI(title="Hello World Agent")

@app.get("/")
def root():
    return {"message": "Hello, World!"}

@app.get("/health")
def health():
    return {"status": "healthy"}
"""

builder = (
    TemplateBuilder("python-fastapi-agent", description="Python FastAPI hello-world agent")
    .from_image("python:3.11-slim")
    .vcpu(2)
    .memory(512)
    .disk(4096)
    .envs({"PYTHONUNBUFFERED": "1"})
    .apt_install("curl")
    .pip_install("fastapi", "uvicorn[standard]")
    .mkdir("/app")
    .copy_file(app_code, "/app/main.py")
    .start_cmd("cd /app && uvicorn main:app --host 0.0.0.0 --port 8080")
    .ready_cmd(TemplateBuilder.wait_for_port(8080), timeout_secs=60)
)

status = client.templates.build_and_wait(
    builder,
    poll_interval_secs=10,
    timeout_secs=600,
)

if status.is_success:
    print(f"Template ID: {status.template_id}")
else:
    print(f"Build failed: {status.error}")

From a Git Repository

Clone a public or private repository directly into the template during the build.
from gravixlayer import GravixLayer, TemplateBuilder

client = GravixLayer(api_key="YOUR_API_KEY")

builder = (
    TemplateBuilder("node-git-repo", description="Node.js app from public Git repo")
    .from_image("node:20-slim")
    .vcpu(2)
    .memory(512)
    .disk(4096)
    .env("NODE_ENV", "production")
    .apt_install("curl", "git")
    .git_clone(
        url="https://github.com/IBM/node-hello-world",
        dest="/app",
        branch="main",
        depth=1,
    )
    .run("cd /app && npm install --production")
    .start_cmd("cd /app && node app.js")
    .ready_cmd(TemplateBuilder.wait_for_port(8080), timeout_secs=60)
)

status = client.templates.build_and_wait(builder, poll_interval_secs=10, timeout_secs=600)
For private repositories, pass an auth_token:
builder = (
    TemplateBuilder("private-app")
    .from_image("python:3.11-slim")
    .git_clone(
        url="https://github.com/your-org/private-repo",
        dest="/app",
        branch="main",
        depth=1,
        auth_token="ghp_xxxxx",  # GitHub PAT or equivalent
    )
    # ... additional build steps
)

From a Local Directory

Copy files and directories from your local machine into the template.
from gravixlayer import GravixLayer, TemplateBuilder

client = GravixLayer(api_key="YOUR_API_KEY")

builder = (
    TemplateBuilder("python-local-project")
    .from_image("python:3.11-slim")
    .vcpu(2)
    .memory(512)
    .copy_file("./requirements.txt", "/app/requirements.txt")
    .copy_dir("./src", "/app/src")
    .pip_install("-r", "/app/requirements.txt")
    .start_cmd("cd /app && python -m src.main")
    .ready_cmd(TemplateBuilder.wait_for_port(8080), timeout_secs=60)
)

status = client.templates.build_and_wait(builder, poll_interval_secs=10, timeout_secs=600)

From a Dockerfile

For full control, provide raw Dockerfile content. When using dockerfile(), handle all setup inside the Dockerfile — you do not need pip_install or apt_install build steps.
from gravixlayer import GravixLayer, TemplateBuilder

client = GravixLayer(api_key="YOUR_API_KEY")

dockerfile_content = """\
FROM python:3.12-slim

RUN apt-get update && apt-get install -y --no-install-recommends \\
    curl git build-essential && \\
    rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir fastapi uvicorn[standard] httpx

WORKDIR /app
COPY <<'EOF' /app/main.py
from fastapi import FastAPI
app = FastAPI()

@app.get("/health")
def health():
    return {"status": "healthy"}
EOF

EXPOSE 8080
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
"""

builder = (
    TemplateBuilder("dockerfile-agent", description="Built from raw Dockerfile")
    .dockerfile(dockerfile_content)
    .vcpu(2)
    .memory(512)
    .start_cmd("uvicorn main:app --host 0.0.0.0 --port 8080")
    .ready_cmd(TemplateBuilder.wait_for_port(8080), timeout_secs=60)
)

status = client.templates.build_and_wait(builder, poll_interval_secs=10, timeout_secs=600)

TemplateBuilder API Reference

Resources

builder.vcpu(2)          # vCPUs (default: 2)
builder.memory(512)      # Memory in MB (default: 512)
builder.disk(4096)       # Disk in MB (default: 4096)

Environment and Tags

builder.env("KEY", "value")              # Single env var
builder.envs({"K1": "v1", "K2": "v2"})  # Multiple env vars
builder.tags({"team": "ml"})             # Metadata tags

Build Steps

builder.run("apt-get update")                          # Shell command
builder.apt_install("curl", "git")                     # System packages
builder.pip_install("fastapi", "uvicorn")              # Python packages
builder.npm_install("express")                         # Node.js packages (global)
builder.mkdir("/app")                                  # Create directory
builder.copy_file("./local/file.py", "/app/file.py")  # Copy local file
builder.copy_file("print('hi')", "/app/hello.py")     # Inline content
builder.copy_dir("./src", "/app/src")                  # Copy directory tree
builder.git_clone(url="https://...", dest="/app")      # Clone repo

Startup and Readiness

builder.start_cmd("uvicorn main:app --host 0.0.0.0 --port 8080")
builder.ready_cmd(TemplateBuilder.wait_for_port(8080), timeout_secs=60)

Building

# Recommended: build and wait for completion
status = client.templates.build_and_wait(
    builder,
    poll_interval_secs=10,
    timeout_secs=600,
    on_status=lambda entry: print(f"[build] {entry.message}"),
)

# Alternative: manual polling
response = client.templates.build(builder)
status = client.templates.get_build_status(response.build_id)

Managing Templates

List Templates

from gravixlayer import GravixLayer

client = GravixLayer(api_key="YOUR_API_KEY")

response = client.templates.list()
print(f"Total templates: {len(response.templates)}")

for t in response.templates:
    print(f"  {t.id}: {t.name}  ({t.vcpu_count} vCPU, {t.memory_mb}MB RAM)")

Get Template Details

info = client.templates.get("TEMPLATE_ID")
print(f"Name: {info.name}")
print(f"Description: {info.description}")
print(f"vCPU: {info.vcpu_count}")
print(f"Memory: {info.memory_mb}MB")
print(f"Disk: {info.disk_size_mb}MB")

Delete a Template

result = client.templates.delete("TEMPLATE_ID")
print(f"Deleted: {result.deleted}")

Next Steps

Create Sandbox

Create a sandbox from a template

Execute Code

Run code in your template environment

Getting Started

Quick start guide with templates

Command Execution

Install packages and run commands