Skip to main content

Introduction

Instance creation on Vast.ai follows a two-step process: first find an offer (an available machine), then accept that offer to create an instance. You can configure instances in two ways:
  • Directly: Pass all configuration (image, environment variables, launch mode, etc.) in the instance creation request
  • From a template: Reference a pre-configured template by its hash_id, optionally overriding specific values
Both approaches use the same endpoint: PUT /api/v0/asks/{offer_id}/. For information about creating and managing templates, see Creating and Using Templates with API.

Instance Creation Fields Reference

When creating an instance, the following fields can be configured:
FieldTypeRequiredDescription
imagestringYes*Docker image path (e.g., vllm/vllm-openai). *Optional when using a template
template_hash_idstringNoTemplate hash ID to use as base configuration
labelstringNoCustom name for the instance
disknumberNoLocal disk partition size in GB (default: 8)
runtypestringNoLaunch mode. SSH/Jupyter runtypes replace the image entrypoint with Vast’s entrypoint; args preserves it. See Runtype and Connection Options
target_statestringNoInitial state: running (default) or stopped
pricenumberNoBid price in $/hour (for interruptible instances only)
envobjectNoEnvironment variables and port mappings as a JSON object (e.g., {"VAR": "val", "-p 8000:8000": "1"})
onstartstringNoShell commands to run after Vast’s entrypoint initializes. Used with SSH/Jupyter runtypes to start your application
args_strstringNoReplaces the image’s Docker CMD. If the image defines an ENTRYPOINT, args_str is passed as arguments to it. Only used with runtype: "args"
use_jupyter_labbooleanNoUse JupyterLab instead of Jupyter Notebook
jupyter_dirstringNoDirectory to launch Jupyter from
python_utf8booleanNoSet Python locale to C.UTF-8
lang_utf8booleanNoSet locale to C.UTF-8
image_loginstringNoDocker registry credentials for private images (eg., -u username -p access_token docker.io)
cancel_unavailbooleanNoCancel if instance cannot start immediately
vmbooleanNoCreate a VM instance instead of a container
volume_infoobjectNoVolume creation or linking configuration

Step 1: Find an Offer

Before creating an instance, search for available machines that match your requirements.
# Search for machines with at least 1 RTX 4090, reliability > 99%
curl -X POST "https://console.vast.ai/api/v0/bundles/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gpu_name": {"in": ["RTX 4090"]},
    "num_gpus": {"gte": 1},
    "reliability": {"gte": 0.99},
    "verified": {"eq": true},
    "rentable": {"eq": true},
    "type": "ondemand",
    "limit": 5
  }'
The offer id returned from search is the value you pass as {offer_id} in the instance creation endpoint.

Step 2: Create the Instance

Option A: Create Instance Directly (No Template)

Pass all configuration parameters directly in the request. At minimum, you must provide the image field. Simple example — create an SSH instance with Ubuntu:
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "ubuntu:22.04",
    "disk": 16,
    "runtype": "ssh_direct"
  }'
Full example — SSH instance running a vLLM inference server:
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "vllm/vllm-openai:latest",
    "label": "vllm-inference-server",
    "disk": 50,
    "runtype": "ssh_direct",
    "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "HF_TOKEN": "hf_xxxYourTokenHere", "-p 8000:8000": "1"},
    "onstart": "vllm serve $MODEL_ID --port 8000"
  }'

Option B: Create Instance from a Template

Reference a template by its hash_id. The template provides default values for all configuration fields, so you don’t need to specify image or other parameters unless you want to override them. Basic template usage — all configuration comes from the template:
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f"
  }'
Template with overrides — use a template but customize specific values:
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f",
    "label": "custom-inference-server",
    "disk": 100,
    "env": {"MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.2", "HF_TOKEN": "hf_xxxYourTokenHere"}
  }'

Runtype and Connection Options

The runtype field controls how you connect to your instance:
RuntypeAuto-provisioned PortsDescription
ssh_direct22 (SSH)Direct SSH connection. Port 22 is provisioned on the instance
ssh_proxyNoneSSH via Vast.ai proxy. No ports provisioned on the instance
sshNoneAlias for ssh_proxy
jupyter_direct8080 (Jupyter) + 22 (SSH)Recommended. Direct Jupyter and SSH access. Ports 8080 and 22 are provisioned on the instance
jupyter_proxyNoneJupyter and SSH via Vast.ai proxy. No ports provisioned on the instance
jupyterNoneAlias for jupyter_proxy
argsNoneContainer runs with the original entrypoint and args_str appended. No SSH/Jupyter
All Jupyter runtypes implicitly include SSH access. Only the _direct runtypes provision ports on the instance itself — jupyter_direct provisions ports 8080 and 22, while ssh_direct provisions port 22. Proxy runtypes route connections through Vast.ai’s infrastructure without opening ports on the instance.
Recommendation: Use runtype: "jupyter_direct" for the most flexibility — you get both direct Jupyter and direct SSH access with ports provisioned on the instance. Use runtype: "ssh_direct" if you only need SSH.

Entrypoint Behavior

How the container starts depends on the runtype:
  • SSH and Jupyter runtypes: The image’s original entrypoint is replaced by Vast’s own entrypoint, which sets up SSH/Jupyter access. Use the onstart field to run your own startup commands (e.g., launching a server). Your onstart script runs after the Vast entrypoint has initialized.
  • args runtype: The image’s original ENTRYPOINT is preserved. The args_str value replaces the image’s Docker CMD — if the image defines an ENTRYPOINT, args_str is passed as arguments to it. If the image has no ENTRYPOINT (only CMD), args_str replaces the command entirely. No SSH or Jupyter access is provisioned.
If you use an SSH or Jupyter runtype without an onstart command, the container will start with only SSH/Jupyter access — your application won’t run automatically. Use onstart to start your services.

Runtype Examples

Jupyter Lab with SSH (recommended) — use onstart to start your application:
{
  "image": "ubuntu:22.04",
  "disk": 16,
  "runtype": "jupyter_direct",
  "use_jupyter_lab": true,
  "jupyter_dir": "/workspace",
  "onstart": "echo 'Instance is ready'"
}
SSH with a vLLM server — the server is started via onstart:
{
  "image": "vllm/vllm-openai:latest",
  "disk": 50,
  "runtype": "ssh_direct",
  "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "-p 8000:8000": "1"},
  "onstart": "vllm serve $MODEL_ID --port 8000"
}
Entrypoint arguments (headless)args_str replaces the image’s CMD and is passed to its ENTRYPOINT:
{
  "image": "vllm/vllm-openai:latest",
  "disk": 50,
  "runtype": "args",
  "args_str": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B --port 8000"
}

Environment Variables and Ports

When creating instances, the env field is a JSON object (dict). Environment variables are key-value pairs, and port mappings use the Docker -p syntax as keys with "1" as the value.
{
  "env": {
    "HF_TOKEN": "hf_xxx123",
    "MODEL_ID": "meta-llama/Llama-3-8B",
    "-p 8000:8000": "1",
    "-p 8080:8080": "1"
  }
}
When using a template, the env dict from your request is merged with the template’s env:
  • Existing keys from the template are retained
  • New keys from the request are added
  • Conflicting keys use the request value
See Precedence Rules in the templates guide for full details.

Instance Pricing

On-Demand Instances

On-demand instances use fixed pricing. Simply omit the price field:
{
  "image": "ubuntu:22.04",
  "disk": 16,
  "runtype": "ssh_direct"
}

Interruptible (Bid) Instances

For lower-cost interruptible instances, set a bid price. Search with type: "bid" to find interruptible offers, then provide the price field:
# Search for interruptible offers
curl -X POST "https://console.vast.ai/api/v0/bundles/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gpu_name": {"in": ["RTX 4090"]},
    "num_gpus": {"gte": 1},
    "verified": {"eq": true},
    "rentable": {"eq": true},
    "type": "bid"
  }'

# Create interruptible instance with bid price
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "ubuntu:22.04",
    "disk": 16,
    "runtype": "ssh_direct",
    "price": 0.20
  }'

Attaching Volumes

Attach persistent storage to your instance using the volume_info field. The volume must already exist — you can create volumes separately via the API or CLI before attaching them to an instance.
You can list your existing volumes with vastai show volumes or the equivalent API call to find the volume_id to use.
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "ubuntu:22.04",
    "disk": 16,
    "runtype": "ssh_direct",
    "volume_info": {
      "volume_id": 12345,
      "mount_path": "/workspace"
    }
  }'

Using Private Docker Images

If your Docker image is hosted in a private registry, provide credentials via the image_login field:
curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "registry.example.com/my-org/my-image:latest",
    "image_login": "-u username -p access_token docker.io",
    "runtype": "ssh_direct"
  }'
When using a template with private registry credentials (docker_login_repo, docker_login_user, docker_login_pass), those credentials carry over to the instance automatically.

End-to-End Example

This example shows the complete workflow: searching for a machine, creating an instance, and checking its status.
# Step 1: Search for offers
OFFERS=$(curl -s -X POST "https://console.vast.ai/api/v0/bundles/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gpu_name": {"in": ["RTX 4090"]},
    "num_gpus": {"gte": 1},
    "gpu_ram": {"gte": 24000},
    "reliability": {"gte": 0.99},
    "verified": {"eq": true},
    "rentable": {"eq": true},
    "type": "ondemand",
    "limit": 3
  }')

echo "Available offers:"
echo "$OFFERS" | jq '.offers[] | {id, gpu_name, num_gpus, dph_total}'

# Step 2: Create instance using the first offer
OFFER_ID=$(echo "$OFFERS" | jq '.offers[0].id')

RESULT=$(curl -s -X PUT "https://console.vast.ai/api/v0/asks/$OFFER_ID/" \
  -H "Authorization: Bearer $VAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "vllm/vllm-openai:latest",
    "label": "my-vllm-server",
    "disk": 50,
    "runtype": "ssh_direct",
    "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "-p 8000:8000": "1"},
    "onstart": "vllm serve $MODEL_ID --port 8000"
  }')

INSTANCE_ID=$(echo "$RESULT" | jq '.new_contract')
echo "Created instance: $INSTANCE_ID"

# Step 3: Check instance status
curl -s "https://console.vast.ai/api/v0/instances/$INSTANCE_ID/" \
  -H "Authorization: Bearer $VAST_API_KEY" | jq '{id: .instances.id, status: .instances.actual_status, label: .instances.label}'

CLI Reference

The Vast.ai CLI provides equivalent commands for instance creation:
CommandDescription
vastai search offers '<filters>'Search for available machines
vastai create instance <offer_id> <image> [options]Create an instance directly
vastai create instance <offer_id> --template_hash <hash>Create an instance from a template
Common create instance options:
  • --image IMAGE - Docker image
  • --template_hash HASH - Template hash ID
  • --disk GB - Disk space in GB
  • --ssh - Launch as SSH instance
  • --direct - Use direct connections
  • --jupyter - Launch as Jupyter instance
  • --jupyter-lab - Use JupyterLab
  • --env ENV - Docker options (env vars and ports)
  • --onstart-cmd CMD - Onstart script
  • --label LABEL - Instance name
  • --price PRICE - Bid price for interruptible instances
  • --link-volume ID - Attach an existing volume
  • --mount-path PATH - Volume mount path
Example CLI commands:
# Direct instance creation
vastai create instance 12345678 vllm/vllm-openai:latest \
  --disk 50 --ssh --direct \
  --env "-e MODEL_ID=deepseek-ai/DeepSeek-R1-Distill-Llama-8B -p 8000:8000" \
  --onstart-cmd "vllm serve \$MODEL_ID --port 8000"

# Instance from template
vastai create instance 12345678 --template_hash 4e17788f74f075dd9aab7d0d4427968f

# Instance from template with overrides
vastai create instance 12345678 --template_hash 4e17788f74f075dd9aab7d0d4427968f \
  --disk 100 \
  --env "-e HF_TOKEN=hf_xxxYourTokenHere"

Common Pitfalls

Ensure you set the correct runtype. For SSH access, use runtype: "ssh_direct" for best results. Also verify that:
  • You have an SSH key registered with Vast.ai (vastai create ssh-key)
  • The machine supports direct connections (most verified machines do)
  • The instance has finished loading (check actual_status is running)
For instance creation, the env field must be a JSON object (dict), not a Docker flag string:
  • Correct: {"VAR1": "value1", "VAR2": "value2"}
  • Wrong: "-e VAR1=value1 -e VAR2=value2"
Port mappings use the -p syntax as keys with "1" as the value: {"-p 8000:8000": "1"}Note: Template creation still uses the Docker flag string format.Also note that environment variables set via env are not automatically visible in SSH sessions. To make them available when you SSH in, add the following to your onstart script:
env >> /etc/environment
This exports all environment variables so they persist across SSH logins.
Offers are dynamic — machines can be rented by others between your search and creation request. Handle this by:
  • Searching for multiple offers and trying the next one if creation fails
  • Using cancel_unavail: true to fail fast if the offer is no longer available
  • Retrying the search to find fresh offers
Interruptible instances can be stopped when someone outbids you. To reduce interruptions:
  • Increase your bid price
  • Choose machines with lower demand
  • Consider on-demand instances for critical workloads (omit price field)
The volume_info field must be included in the instance creation request, not just the template. Template volume_info is a UI hint only.The volume must already exist before you can attach it. Ensure you provide the correct structure:
{
  "volume_info": {
    "volume_id": 12345,
    "mount_path": "/workspace"
  }
}
Where volume_id is the ID of an existing volume from vastai show volumes.