> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hopx.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Building

> Create custom templates with dependencies in HopX. Build custom sandbox templates from Docker images, configure resources, add build steps, and install dependencies. Learn how to use TemplateBuilder to create templates tailored to your needs. Includes Python and JavaScript SDK examples and REST API endpoints.

Build custom templates with pre-configured environments, dependencies, and settings. Templates allow you to create reusable sandbox configurations.

## Prerequisites

Before you begin, make sure you have:

* **HopX API key** - Get one from [console.hopx.dev](https://console.hopx.dev) or see \[API key Management]\(/API key)
* **Understanding of templates** - Familiarity with [Listing Templates](/core-concepts/templates/listing) is helpful
* **Base image or template** - Decide on a base image (Python, Node.js, Ubuntu, etc.)
* **Dependencies list** - Know what packages or tools you want pre-installed

## Overview

Building templates enables you to:

* Pre-install packages and dependencies
* Configure environment variables
* Set up working directories and users
* Create reusable sandbox configurations
* Optimize sandbox creation time

<Note>
  Template building is an async operation that can take several minutes. The build process includes uploading files, executing build steps, and waiting for template activation.
</Note>

## Basic Template Building

Create a simple template from a base image:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from hopx_ai.template import Template, BuildOptions
    import os

    # Create template from base image
    template = Template()
    template.from_python_image("3.11-slim")

    # Add build steps
    template.run_cmd("pip install numpy pandas matplotlib")

    # Build template
    options = BuildOptions(
        name="my-python-template",
        api_key=os.getenv("HOPX_API_KEY"),
        cpu=2,
        memory=2048,
        disk_gb=10,
        context_path=os.getcwd()  # Required: working directory for file operations
    )

    result = await Template.build(template, options)
    print(f"Template built: {result.template_id}")
    print(f"Build ID: {result.build_id}")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Note: JavaScript SDK template building may have different API
    // This is a conceptual example based on Python SDK patterns

    import { Template, BuildOptions } from '@hopx-ai/sdk';

    // Create template from base image
    const template = new Template('python:3.11-slim');

    // Add build steps
    template.runCmd('pip install numpy pandas matplotlib');

    // Build template
    const options = new BuildOptions({
      name: 'my-python-template',
      apiKey: process.env.HOPX_API_KEY,
      cpu: 2,
      memory: 2048,
      diskGb: 10
    });

    const result = await Template.build(template, options);
    console.log(`Template built: ${result.templateId}`);
    ```
  </Tab>
</Tabs>

## Using Base Image Helpers

Use convenient base image helpers:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from hopx_ai.template import Template, BuildOptions
    import os

    # From Ubuntu
    template = Template().from_ubuntu_image("22.04")
    template.apt_install("curl", "git", "vim")

    # From Python
    template = Template().from_python_image("3.11")
    template.pip_install("numpy", "pandas")

    # From Node.js
    template = Template().from_node_image("20")
    template.npm_install("typescript", "tsx")

    # Build
    options = BuildOptions(
        name="my-template",
        api_key=os.getenv("HOPX_API_KEY"),
        context_path=os.getcwd()
    )
    result = await Template.build(template, options)
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Conceptual example
    import { Template, BuildOptions } from '@hopx-ai/sdk';

    // From Ubuntu
    const template = new Template().fromUbuntuImage('22.04');
    template.aptInstall('curl', 'git', 'vim');

    // From Python
    const template2 = new Template().fromPythonImage('3.11');
    template2.pipInstall('numpy', 'pandas');

    // From Node.js
    const template3 = new Template().fromNodeImage('20');
    template3.npmInstall('typescript', 'tsx');
    ```
  </Tab>
</Tabs>

## Complete Template Example

Build a complete template with multiple steps:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from hopx_ai.template import Template, BuildOptions
    from hopx_ai.template.ready_checks import wait_for_port
    import os

    # Create template
    template = Template()
    template.from_python_image("3.11-slim")

    # Install system packages
    template.apt_install("curl", "git", "build-essential")

    # Set working directory
    template.set_workdir("/app")

    # Install Python packages
    template.pip_install("flask", "gunicorn", "redis")

    # Set environment variables
    template.set_env("FLASK_ENV", "production")
    template.set_env("PORT", "8000")

    # Copy files (requires file upload)
    # template.copy("/local/path", "/app", options=CopyOptions(owner="appuser"))

    # Set start command and ready check
    template.set_start_cmd(
        "gunicorn -w 4 -b 0.0.0.0:8000 app:app",
        ready=wait_for_port(8000, timeout=30000)
    )

    # Build template
    options = BuildOptions(
        name="flask-app-template",
        api_key=os.getenv("HOPX_API_KEY"),
        cpu=2,
        memory=2048,
        disk_gb=10,
        context_path=os.getcwd()  # Required for file operations
    )

    result = await Template.build(template, options)
    print(f"✅ Template built: {result.template_id}")
    print(f"   Build ID: {result.build_id}")
    print(f"   Duration: {result.duration}s")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Conceptual example
    import { Template, BuildOptions, waitForPort } from '@hopx-ai/sdk';

    const template = new Template('python:3.11-slim');

    // Install system packages
    template.aptInstall('curl', 'git', 'build-essential');

    // Set working directory
    template.setWorkdir('/app');

    // Install Python packages
    template.pipInstall('flask', 'gunicorn', 'redis');

    // Set environment variables
    template.setEnv('FLASK_ENV', 'production');
    template.setEnv('PORT', '8000');

    // Set start command and ready check
    template.setStartCmd(
      'gunicorn -w 4 -b 0.0.0.0:8000 app:app',
      waitForPort(8000, { timeout: 30000 })
    );

    // Build template
    const options = new BuildOptions({
      name: 'flask-app-template',
      apiKey: process.env.HOPX_API_KEY,
      cpu: 2,
      memory: 2048,
      diskGb: 10
    });

    const result = await Template.build(template, options);
    console.log(`✅ Template built: ${result.templateId}`);
    ```
  </Tab>
</Tabs>

## Build Options

Configure build options:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from hopx_ai.template import BuildOptions
    import os

    options = BuildOptions(
        name="my-template",              # Required: Template name
        api_key=os.getenv("HOPX_API_KEY"),  # Required: API key
        cpu=2,                           # CPU cores (default: 2)
        memory=2048,                     # Memory in MB (default: 2048)
        disk_gb=10,                      # Disk in GB (default: 10)
        context_path=os.getcwd(),        # Required: Working directory for file operations
        skip_cache=False,                # Skip build cache (default: False)
        update=False,                    # Update existing template (default: False)
        template_activation_timeout=2700  # Max wait for activation in seconds (default: 2700)
    )

    # With progress callbacks
    def on_progress(progress: int):
        print(f"Build progress: {progress}%")

    def on_log(log_entry: dict):
        print(f"[{log_entry['level']}] {log_entry['message']}")

    options.on_progress = on_progress
    options.on_log = on_log
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Conceptual example
    const options = new BuildOptions({
      name: 'my-template',              // Required: Template name
      apiKey: process.env.HOPX_API_KEY, // Required: API key
      cpu: 2,                           // CPU cores (default: 2)
      memory: 2048,                     // Memory in MB (default: 2048)
      diskGb: 10,                       // Disk in GB (default: 10)
      skipCache: false,                 // Skip build cache (default: false)
      update: false,                    // Update existing template (default: false)
      templateActivationTimeout: 2700,  // Max wait for activation in seconds
      onProgress: (progress) => {
        console.log(`Build progress: ${progress}%`);
      },
      onLog: (logEntry) => {
        console.log(`[${logEntry.level}] ${logEntry.message}`);
      }
    });
    ```
  </Tab>
</Tabs>

## Build Result and Logs

Access build results and logs:

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from hopx_ai.template import Template, BuildOptions
    import os

    # Build template
    template = Template()
    template.from_python_image("3.11-slim")
    template.pip_install("numpy")

    options = BuildOptions(
        name="test-template",
        api_key=os.getenv("HOPX_API_KEY"),
        context_path=os.getcwd()
    )

    result = await Template.build(template, options)

    # Access build information
    print(f"Build ID: {result.build_id}")
    print(f"Template ID: {result.template_id}")
    print(f"Duration: {result.duration}s")

    # Get build logs
    logs = await result.get_logs()
    print(f"Logs:\n{logs.logs}")

    # Poll for new logs
    if not logs.complete:
        new_logs = await result.get_logs(offset=logs.offset)
        print(f"New logs:\n{new_logs.logs}")
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    // Conceptual example
    const result = await Template.build(template, options);

    // Access build information
    console.log(`Build ID: ${result.buildId}`);
    console.log(`Template ID: ${result.templateId}`);
    console.log(`Duration: ${result.duration}s`);

    // Get build logs
    const logs = await result.getLogs();
    console.log(`Logs:\n${logs.logs}`);

    // Poll for new logs
    if (!logs.complete) {
      const newLogs = await result.getLogs({ offset: logs.offset });
      console.log(`New logs:\n${newLogs.logs}`);
    }
    ```
  </Tab>
</Tabs>

## Best Practices

<Steps>
  <Step title="1. Start with Base Images">
    Use base image helpers (from\_python\_image, from\_node\_image) for common environments.
  </Step>

  <Step title="2. Chain Operations">
    Use fluent API to chain operations for readable template definitions.
  </Step>

  <Step title="3. Set Resources Appropriately">
    Configure CPU, memory, and disk based on your application needs.
  </Step>

  <Step title="4. Use Ready Checks">
    Set ready checks for services that need to be ready before sandbox is usable.
  </Step>

  <Step title="5. Monitor Build Progress">
    Use progress and log callbacks to monitor long-running builds.
  </Step>
</Steps>

## Related

* **[Listing Templates](/core-concepts/templates/listing)** - List available templates
* **[Getting Template Details](/core-concepts/templates/getting-details)** - View template information
* **[Template Configuration](/core-concepts/templates/configuration)** - Configure template resources and steps
* **API**: [POST /v1/templates/build](/api/control-plane/build-template) - Control Plane API endpoint
* [CLI Template Commands](/cli/commands/template) - Template management from CLI

## Next Steps

* Learn about [Template Configuration](/core-concepts/templates/configuration) for advanced setup
* Explore [Template Caching](/core-concepts/templates/caching) for build optimization
* Review [Listing Templates](/core-concepts/templates/listing) to see your built templates
