Skip to content

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:

ToolBest forState
Terraform providerTeams that already manage infrastructure with Terraform or OpenTofu. In preview — build it from source.A Terraform state file.
TypeScript SDKA setup script that creates a whole stack, with full types and error handling.None — the script looks up what exists.
CLIOne-off provisioning from a shell script or Makefile.None — the script looks up what exists.
hoststack.yamlA 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:

bash
cd packages/terraform-provider-hoststack
go build -o terraform-provider-hoststack

Then 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.

~/.terraformrc
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
stringrequired

An API key, hs_live_.... Or set HOSTSTACK_API_KEY. It needs full_access permission to set environment variables — see Teams & roles.

team_id
stringrequired

Your numeric team ID — the one the API key belongs to. Or set HOSTSTACK_TEAM_ID. Find it as Team ID in the output of hoststack whoami.

endpoint
string

The API's base URL. Or set HOSTSTACK_API_URL.

Default: https://hoststack.dev

Example

main.tf
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.

ResourceArgumentsRead-only
hoststack_projectname (required), description, regionid, slug
hoststack_serviceproject_id, name, type (required); runtime, plan, branch, build_command, start_command, health_check_path, auto_deployid
hoststack_databaseproject_id, name, engine (required); plan, regionid, status
hoststack_domainservice_id, domain (required); ssl_enabledid, status
hoststack_env_varservice_id, key, value (required, sensitive); target (build, runtime or both, default both), is_secretid

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_service has 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_path only 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 import isn't supported, so the provider only manages resources it created.
  • hoststack_domain can't be refreshed. It creates the domain, but a later plan fails to read it back. Add domains in the dashboard or with hoststack domains add for now.
  • Secret values aren't read back. For a hoststack_env_var with is_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',
  });
}

Once 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?

Essential cookies only — for login sessions. No tracking. Details