Terraform
Create HostStack projects, services, databases and environment variables from code — with the Terraform provider, or with a short SDK or CLI script.
Choose a tool
Every option talks to the same API with an API key from Settings → API keys. Pick the one that matches how you provision the rest of your stack:
| Tool | Best for | State |
|---|---|---|
| Terraform provider | Teams that already manage infrastructure with Terraform or OpenTofu. In preview — build it from source. | A Terraform state file. |
| TypeScript SDK | A setup script that creates a whole stack, with full types and error handling. | None — the script looks up what exists. |
| CLI | One-off provisioning from a shell script or Makefile. | None — the script looks up what exists. |
| hoststack.yaml | A service's build, start, port, health check and disk, kept in its repo. It configures a service; it doesn't create one. | Your Git history. |
The Terraform provider
Build and install it
The provider is written in Go and lives in packages/terraform-provider-hoststack. With Go installed:
cd packages/terraform-provider-hoststack
go build -o terraform-provider-hoststackThen tell Terraform to use that binary instead of the registry with a dev_overrides block in your CLI configuration (~/.terraformrc). Terraform 1.5 or later is required.
provider_installation {
dev_overrides {
"hoststack/hoststack" = "/path/to/packages/terraform-provider-hoststack"
}
direct {}
}With an override in place, skip terraform init and run terraform plan and terraform apply directly. See HashiCorp's development overrides guide for the details.
Configure it
Each setting can go in the provider block or in an environment variable. A value in the block wins.
api_key stringrequiredAn API key,
hs_live_.... Or setHOSTSTACK_API_KEY. It needsfull_accesspermission to set environment variables — see Teams & roles.team_id stringrequiredYour numeric team ID — the one the API key belongs to. Or set
HOSTSTACK_TEAM_ID. Find it as Team ID in the output ofhoststack whoami.endpointstringThe API's base URL. Or set
HOSTSTACK_API_URL.Default:
https://hoststack.dev
Example
terraform {
required_providers {
hoststack = {
source = "hoststack/hoststack"
}
}
}
provider "hoststack" {
# api_key and team_id come from HOSTSTACK_API_KEY and HOSTSTACK_TEAM_ID
}
resource "hoststack_project" "app" {
name = "my-app"
}
resource "hoststack_service" "api" {
project_id = hoststack_project.app.id
name = "api"
type = "web_service"
runtime = "node"
build_command = "npm run build"
start_command = "npm start"
}
resource "hoststack_database" "db" {
project_id = hoststack_project.app.id
name = "app-db"
engine = "postgres"
plan = "starter"
}
resource "hoststack_env_var" "log_level" {
service_id = hoststack_service.api.id
key = "LOG_LEVEL"
value = "info"
}Resources
IDs in the provider are HostStack's numeric IDs, not the prj_... and svc_... IDs the dashboard shows. Reference them from other resources (hoststack_project.app.id) rather than typing them.
| Resource | Arguments | Read-only |
|---|---|---|
| hoststack_project | name (required), description, region | id, slug |
| hoststack_service | project_id, name, type (required); runtime, plan, branch, build_command, start_command, health_check_path, auto_deploy | id |
| hoststack_database | project_id, name, engine (required); plan, region | id, status |
| hoststack_domain | service_id, domain (required); ssl_enabled | id, status |
| hoststack_env_var | service_id, key, value (required, sensitive); target (build, runtime or both, default both), is_secret | id |
type is one of web_service, private_service, worker, cron_job or static_site. engine is one of postgres, mysql, mariadb, mongodb or redis; plan for a database is micro, starter (the default), standard or pro.
Limits of the preview
The provider covers the basics. Before you rely on it, know what it doesn't do yet:
- A service has no source.
hoststack_servicehas no argument for a repository, so the service it creates has nothing to deploy. Connect the repository in the service's settings afterwards, or create services with the SDK or CLI instead. health_check_pathonly applies on update. It is ignored when the service is created; change it once after the first apply, or set it in hoststack.yaml.- No imports.
terraform importisn't supported, so the provider only manages resources it created. hoststack_domaincan't be refreshed. It creates the domain, but a later plan fails to read it back. Add domains in the dashboard or withhoststack domains addfor now.- Secret values aren't read back. For a
hoststack_env_varwithis_secret = true, Terraform keeps the value from your configuration, so a change made in the dashboard isn't detected.
Provision with a script
Without Terraform, a short script does the same job. HostStack keeps no state file for you, so make the script safe to re-run: look each resource up by name before creating it. Project and database names aren't unique, so creating blindly twice gives you two; a service name is unique within a project, and a second create fails with 409 Conflict.
import { HostStack } from '@hoststack.dev/sdk';
const hs = new HostStack({ apiKey: process.env.HOSTSTACK_API_KEY! });
const teamId = Number(process.env.HOSTSTACK_TEAM_ID); // "Team ID" in: hoststack whoami
// Look up before creating, so running the script twice changes nothing.
const { projects } = await hs.projects.list(teamId);
const project =
projects.find((p) => p.name === 'billing') ??
(await hs.projects.create(teamId, { name: 'billing' })).project;
const { services } = await hs.services.list(teamId, { projectId: project.id });
if (!services.some((s) => s.name === 'api')) {
// Creating a service with a repo starts its first deploy.
await hs.services.create(teamId, {
projectId: project.id,
name: 'api',
type: 'web_service',
githubRepo: 'acme/billing-api',
branch: 'main',
});
}
const { databases } = await hs.databases.list(teamId, project.id);
if (!databases.some((d) => d.name === 'app-db')) {
await hs.databases.create(teamId, {
projectId: project.id,
name: 'app-db',
engine: 'postgres',
plan: 'starter',
});
}#!/usr/bin/env bash
set -euo pipefail
hoststack login --key "$HOSTSTACK_API_KEY"
project_id() {
hoststack projects list --json | jq -r '.[] | select(.name == "billing") | .publicId' | head -n1
}
[ -n "$(project_id)" ] || hoststack projects create --name billing
PROJECT=$(project_id)
hoststack services create --name api --type web_service \
--project "$PROJECT" --repo acme/billing-api --branch main
hoststack db create --project "$PROJECT" --name app-db \
--engine postgres --plan starterOnce the service exists, keep its build, start and health-check settings in a hoststack.yaml in the repository, and its secrets in environment variables — hoststack env set svc_... KEY=value --secret.
Next steps
Was this page helpful?