Sign up

Docs

Everything you need to go from code to live URL.

Install

Works on macOS, Linux and Windows (Intel and ARM). Download and inspect the installer before executing it; the installer then verifies the independently signed release record and archive digest.

macOS / Linux

$ installer="$(mktemp)"
$ curl --fail --show-error --location --proto '=https' --proto-redir '=https' --tlsv1.2 \
    https://innstance.impossibuild.ai/install --output "$installer"
$ less "$installer"
$ sh "$installer"
$ rm -f "$installer"

The binary installs to ~/.local/bin/innstance, with ifhost beside it as a link to the same file. Make sure that directory is in your PATH.

# Add to ~/.zshrc or ~/.bashrc if needed
export PATH="$HOME/.local/bin:$PATH"

Windows (PowerShell)

PS> $installer = Join-Path ([IO.Path]::GetTempPath()) "innstance-install-$([guid]::NewGuid()).ps1"
PS> Invoke-WebRequest -Uri https://innstance.impossibuild.ai/install.ps1 -MaximumRedirection 0 -TimeoutSec 60 -OutFile $installer
PS> Get-Content $installer
PS> & $installer
PS> Remove-Item $installer

The binary installs to %LOCALAPPDATA%\innstance\innstance.exe, with ifhost.exe beside it, and the installer adds that folder to your user PATH itself — open a new terminal for it to take effect. Signature verification uses ssh-keygen from the Windows OpenSSH Client; if the installer reports it missing, run Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 in an elevated PowerShell, then retry.

Login / Logout / Switch Account

For normal production use, run innstance login below. Only when using staging or a self-hosted environment, set its API URL in your current terminal first and use an account and token belonging to that environment.

# macOS / Linux
export IMPOSSIBLE_API_URL=https://innstance.impossibuild.ai
# Windows PowerShell
$env:IMPOSSIBLE_API_URL = "https://innstance.impossibuild.ai"

Sign in (interactive)

$ innstance login
  Opening your browser to sign in...
  (pick your account, approve)

  Logged in as you@email.com

Login via token (CI / agents)

$ printf '%s' "$IFHOST_TOKEN" | innstance login --token -
# Or read a mounted/local secret file:
$ innstance login --from-file /run/secrets/innstance-token

On Windows the same two forms are $env:IFHOST_TOKEN | innstance login --token - and innstance login --from-file C:\path\to\token.txt.

In CI, inject IMPOSSIBLE_API_TOKEN with the CI provider's secret store. Do not put a token literal in a command, repository file, or workflow.

Multiple accounts

You can log in to multiple accounts. Each login is saved as a profile.

# Log in to a second account
$ innstance login
Logged in as work@company.com

# Switch between accounts
$ innstance login --switch
Accounts:
  * [1] you@email.com
    [2] work@company.com

Enter number: 2
Switched to: work@company.com

Logout

$ innstance logout
Logged out: work@company.com
Switched to: you@email.com

Removes the active account. If other profiles remain, switches to the next one.

Tip: Credentials are saved at ~/.impossible/credentials.json (%USERPROFILE%\.impossible\credentials.json on Windows). Supports multiple profiles with one active. The IMPOSSIBLE_API_TOKEN env var overrides the file (useful for CI).

Deploy a runner

innstance deploy provisions or reuses a shell VM. Uploading code, installing dependencies and starting the application are explicit steps. Static HTML, PDF and image projects can use innstance publish instead.

Choose resources and boot the machine

$ innstance init --app my-app --port 3000 --memory 512 --autostop=false --min-machines 1
$ innstance deploy --yes

Read the project's README to choose its port, dependencies and start command. Keep persistent application data under a mounted volume such as /data; use --storage local when initializing an app that needs it.

Upload and install

$ innstance machines push --app my-app . --to /app
$ innstance machines install --app my-app <apt-package> --max-wait 6m

Install the runtime packages your project requires, then run its package-manager setup and migrations with innstance machines exec. An installation success confirms installed packages, not application readiness.

Start and verify the application

$ innstance machines exec --app my-app -- sh -c 'cd /app && setsid nohup <start-command> </dev/null >/tmp/app.log 2>&1 &'
$ innstance status

Replace <start-command> with the project's actual command. Bind the server to 0.0.0.0 on the configured port, inspect its logs, and check the app URL returned by the API before reporting it live. Use innstance machines console for interactive setup.

Replacing a runner machine does not recreate its installed tools or application process. Preserve needed data on the volume and retain reproducible setup commands.

Account Overview

Example output below includes existing legacy multi-machine apps. New runner apps use one machine. Hostnames are placeholders: use the URL returned for your app.

$ innstance status
Logged in as: you@email.com
Plan:         pro

Apps (2):

  my-app
    URL:      https://<assigned-hostname>
    Status:   deployed   Region: iad
    Running:  d8967e0f
    Standby:  a1b2c3d4

  api-backend
    URL:      https://<another-assigned-hostname>
    Status:   deployed   Region: sin
    Running:  e3f4a5b6

Shows your login, plan, and every app grouped with its URL, status, region, and current machine IDs. No --app needed.

For agents: innstance status --json is the fastest way to discover machine IDs for machines exec --machine <id> or machines console start. Pipe to jq.

Machines

All app-specific commands live under innstance machines.

List machines

$ innstance machines --app my-app
Machines for 'my-app' (2): 1 running, 1 stopped

Running:
  d8967e0f  sweet-surf-1234  started  iad  shared/1  256MB  created 2d ago

Standby:
  a1b2c3d4  proud-moon-5678  stopped  iad  shared/1  256MB  created 2d ago

Grouped by state (Running vs Standby), with machine name and age so you can tell replicas apart. Use any listed ID with --machine <id> on exec, or target all at once with start / stop / restart.

Start / Stop / Restart

$ innstance machines stop --app my-app      # Stop all machines
$ innstance machines start --app my-app     # Start them back up
$ innstance machines restart --app my-app   # Restart with fresh env/secrets

Environment Variables

Non-sensitive config - injected into your container's environment at runtime.

# Stage one or more; pass --restart to apply immediately
$ innstance machines env set NODE_ENV=production PORT=3000 --app my-app
Set 2 environment variable(s)

# List all
$ innstance machines env list --app my-app
NODE_ENV=production
PORT=3000

# Inline during deploy (repeatable)
$ innstance deploy --app my-app --env NODE_ENV=production --env PORT=3000

Secrets

For sensitive values (API keys, database URLs, tokens). Values are read from environment variables, files, or stdin—never literal command arguments—and are never returned by the API. Changes are staged until you restart, unless you pass --restart.

# Set secrets from protected sources
$ innstance machines secrets set DATABASE_URL=@env:DATABASE_URL API_KEY=@file:/secure/api-key --app my-app
Set 2 secret(s)

# List (keys only - values never shown)
$ innstance machines secrets list --app my-app
API_KEY
DATABASE_URL

# Read one secret from stdin during deploy
$ printf %s "$STRIPE_KEY" | innstance deploy --app my-app --secret STRIPE_KEY=@stdin
Never put literal secrets in: impossible.toml, Dockerfile ENV, or CLI arguments. Use @env:NAME, @file:PATH, or @stdin. A tracked [secrets] config is refused and the config file is excluded from uploads.

Custom Domains

Run the add command and follow the DNS records it returns. If ownership is not verified yet, add the requested TXT record, keep it in DNS, and run the command again. Use the returned routing target; do not derive it from the app name or its public URL.

$ innstance machines domains add myapp.example.com --app my-app

# After adding the returned DNS records, retry
$ innstance machines domains add myapp.example.com --app my-app

# List domains and recorded TLS status
$ innstance machines domains list --app my-app

# Remove
$ innstance machines domains rm myapp.example.com --app my-app

TLS certificates are provisioned automatically via Let's Encrypt after you add the CNAME record.

Runner capacity

Runner apps use one machine. Manual replica scaling and autoscale commands are not available in the current CLI. A persistent volume attaches to that one machine.

To change CPU or memory, edit [resources] in impossible.toml, then run innstance apply from that project directory. The account plan and available pool limit the requested resources.

$ innstance apply
$ innstance machines --app my-app

Keep [service] autostop = false and min_machines = 1 for a manually started application unless it is prepared to recover through the stop/start lifecycle. A started machine alone does not prove that the application is serving requests.

Persistent Volumes (advanced)

A persistent volume stores data for one machine. Each machine can attach one volume. Store data that must survive replacement under its mount path.

Volumes provide a local disk that survives redeploys, attached to one machine:

$ innstance machines volumes create data --mount /data --size 5 --app my-app
Created volume 'data' (5GB) mounted at /data

$ innstance machines volumes list --app my-app
  data  5GB  /data  iad

$ innstance machines volumes rm data --app my-app

Volume limitations

  • 1 volume = 1 machine. A runner supports one primary volume on its one machine; it cannot share that volume across machines.
  • Fixed size. You choose the size at creation (charged even if empty). Can grow but not shrink.
  • Region-locked. Volume lives in one region; machine must be in the same region.

When to use a volume

Use caseRecommended
SQLite database (single machine)Volume
Local config / state for one machineVolume
User uploads, images, filesExternal S3 (Tigris, Cloudflare R2, AWS S3) - bring your own bucket and credentials
Postgres / MySQLManaged DB (Supabase, Neon)
Cache / RedisManaged Redis (Upstash)

Logs

Default: live stream (like tail -f), runs until Ctrl+C. Add --since or --lines to fetch historical logs and exit immediately. Filters work in both modes.

# Live tail - runs forever
$ innstance machines logs --app my-app

# Last hour, then exit
$ innstance machines logs --app my-app --since 1h

# Last 50 lines, then exit
$ innstance machines logs --app my-app --lines 50

# Filter by substring (streaming or historical)
$ innstance machines logs --app my-app --grep "ERROR"

# Filter by level (error = error/fatal/panic lines)
$ innstance machines logs --app my-app --level error

# Combined filters + historical window
$ innstance machines logs --app my-app --grep "GET" --lines 50

# Structured JSON, one object per line (for jq)
$ innstance machines logs --app my-app --json

Exec (run commands inside your app)

Run any command inside your running container. Useful for debugging, inspecting files, running migrations, or checking configuration.

$ innstance machines exec --app my-app -- ls /data
$ innstance machines exec --app my-app -- env
$ innstance machines exec --app my-app -- cat /etc/nginx/nginx.conf
$ innstance machines exec --app my-app -- python manage.py migrate
$ innstance machines exec --app my-app -- sh -c "du -sh /data/*"

# Multi-machine apps: target a specific machine by ID
$ innstance machines --app my-app                     # list machines with their IDs
$ innstance machines exec --app my-app --machine 32d41... -- ps -ef
For agents: Use exec to inspect the runner, run setup commands, or diagnose the application. Available tools depend on what has been installed. Use --machine to select an owned machine explicitly.
Limitations:
  • Use a console session for long-running or interactive commands
  • No interactive terminal (no vim, htop, tmux). Use for one-off commands only.
  • Machine must be running - start it first with innstance machines start
  • Install missing tools before invoking them through exec

Destroy

$ innstance machines destroy --app my-app --yes-irreversible  # Permanently delete app and all resources

Apply saved configuration

Environment and secret saves update stored configuration. innstance apply synchronizes resource edits from the current project's impossible.toml and applies CPU, memory, environment and secrets to the machine without a new deployment build. The machine restarts, so verify the application afterward.

$ innstance machines env set LOG_LEVEL=debug --app my-app
$ innstance apply --app my-app

Inspect the result for failed machine IDs. JSON output includes applied and failed_machines; the CLI's partial-result exit status alone does not establish that every machine succeeded.

Config File

innstance deploy requires impossible.toml in the current project directory. Run innstance init to create it, then edit the settings for your app. Supported command flags override the corresponding file settings for that invocation.

app = "my-app"
region = "iad"

[service]
  internal_port = 3000
  autostop = false
  min_machines = 1

[resources]
  cpu_kind = "shared"     # "shared" or "performance" (performance on Pro and Team)
  cpus = 1                # 1, 2, 4, 8 (your plan caps the max)
  memory_mb = 256         # 256, 512, 1024, 2048, ...

[env]
  NODE_ENV = "production" # Non-sensitive only!

With this file in your repo, deploys are just:

$ innstance deploy

Update & Version

Check version

$ innstance version
innstance build: 20260416-024938
Up to date.

Compares your local build with the latest on the server. If outdated:

$ innstance version
innstance build: 20260101-000000
Update available: 20260101-000000 -> 20260416-024938
Run 'innstance update' to install.

Update

$ innstance update
Checking for updates...
Updated: /Users/you/.local/bin/innstance

Downloads the latest binary for your OS/arch and replaces the current one in-place (%LOCALAPPDATA%\innstance\innstance.exe on Windows).

Tip: innstance status also shows your CLI version and a hint if an update is available - no need to check manually.

For AI Agents

Innstance is designed to be used by AI coding agents. Key features:

  • --json flag on every command - structured output to stdout, logs to stderr
  • --yes skips ordinary confirmation prompts. Destructive actions and egress consent still require their explicit flags, such as --yes-irreversible and --yes-egress.
  • IMPOSSIBLE_API_TOKEN env var - no interactive login needed
  • Clear exit codes - 0 success, non-zero failure
  • Error messages include what to do next
# Agent workflow: deploy and get URL as JSON
$ innstance deploy --app my-app --json
{"id":"01ABC...","status":"live","url":"https://<assigned-hostname>","machines":1}

# Check account status
$ innstance status --json
{"email":"you@email.com","plan":"free","apps":[{"name":"my-app","status":"deployed",...}]}

For the complete API reference (all endpoints, request/response shapes), see /llms.txt.