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.
~/.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.
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.
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
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 case | Recommended |
|---|---|
| SQLite database (single machine) | Volume |
| Local config / state for one machine | Volume |
| User uploads, images, files | External S3 (Tigris, Cloudflare R2, AWS S3) - bring your own bucket and credentials |
| Postgres / MySQL | Managed DB (Supabase, Neon) |
| Cache / Redis | Managed 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
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.- 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).
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:
--jsonflag on every command - structured output to stdout, logs to stderr--yesskips ordinary confirmation prompts. Destructive actions and egress consent still require their explicit flags, such as--yes-irreversibleand--yes-egress.IMPOSSIBLE_API_TOKENenv 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.