Loading...
Loading...
Manage Spice.ai Cloud infrastructure with Terraform or OpenTofu. Use when writing Terraform configs for Spice apps, deployments, secrets, members, or when importing existing Spice.ai resources into Terraform state.
npx skill4agent add spiceai/skills spice-terraformspiceai/spiceaiterraform {
required_providers {
spiceai = {
source = "spiceai/spiceai"
version = "~> 0.1"
}
}
}
provider "spiceai" {
client_id = var.spiceai_client_id
client_secret = var.spiceai_client_secret
# api_endpoint = "https://api.spice.ai" # optional, this is the default
}client_idclient_secretSPICEAI_CLIENT_IDSPICEAI_CLIENT_SECRETexport SPICEAI_CLIENT_ID="your-client-id"
export SPICEAI_CLIENT_SECRET="your-client-secret"
terraform plandata "spiceai_regions" "available" {}
resource "spiceai_app" "analytics" {
name = "analytics-app"
cname = data.spiceai_regions.available.default
description = "Production analytics"
visibility = "private"
replicas = 2
image_tag = "1.5.0-models"
spicepod = yamlencode({
version = "v1"
kind = "Spicepod"
name = "analytics-app"
datasets = [{
from = "postgres:public.events"
name = "events"
params = {
pg_host = "db.example.com"
pg_user = "$${secrets:PG_USER}"
pg_pass = "$${secrets:PG_PASS}"
}
acceleration = {
enabled = true
engine = "duckdb"
refresh_check_interval = "5m"
}
}]
})
}| Argument | Type | Required | Notes |
|---|---|---|---|
| string | Yes | Min 4 chars, alphanumeric + hyphens |
| string | Yes | Region identifier (from |
| string | No | |
| string | No | |
| string | No | YAML or JSON spicepod configuration |
| string | No | Spice runtime version tag |
| number | No | 1-10 |
| string | No | AWS region code |
| string | No | Git branch for production deployments |
| string | No | Kubernetes node group |
| number | No | Persistent volume size in GB |
idapi_keycreated_attriggersresource "spiceai_deployment" "current" {
app_id = spiceai_app.analytics.id
commit_message = "Deploy analytics app"
triggers = {
spicepod = spiceai_app.analytics.spicepod
image_tag = spiceai_app.analytics.image_tag
replicas = spiceai_app.analytics.replicas
}
}| Argument | Type | Required | Notes |
|---|---|---|---|
| string | Yes | App ID to deploy |
| string | No | Override runtime image |
| number | No | Override replicas (1-10) |
| boolean | No | Enable debug mode (default: false) |
| string | No | Git branch for tracking |
| string | No | Git commit SHA |
| string | No | Deployment description |
idstatusqueuedin_progresssucceededfailederror_messagecreated_attriggersvariable "secrets" {
type = map(string)
sensitive = true
default = {
PG_USER = "analytics"
PG_PASS = "secret123"
OPENAI_API_KEY = "sk-..."
}
}
resource "spiceai_secret" "app_secrets" {
for_each = var.secrets
app_id = spiceai_app.analytics.id
name = each.key
value = each.value
}| Argument | Type | Required | Notes |
|---|---|---|---|
| string | Yes | |
| string | Yes | Start with letter/underscore, alphanumeric + |
| string | Yes | Sensitive. Must set manually after import (API masks values) |
idvariable "team" {
type = set(string)
default = ["alice", "bob"]
}
resource "spiceai_member" "team" {
for_each = var.team
username = each.key
roles = ["member"]
}| Argument | Type | Required | Notes |
|---|---|---|---|
| string | Yes | GitHub username |
| string[] | No | Default: |
user_iddata "spiceai_regions" "available" {}
# Use: data.spiceai_regions.available.default
# Use: data.spiceai_regions.available.regions[*].cnameregionsnameregioncnameproviderproviderNamedefaultdata "spiceai_container_images" "stable" {
channel = "stable" # or "enterprise"
}
# Use: data.spiceai_container_images.stable.default
# Use: data.spiceai_container_images.stable.images[*].tagimagesnametagchanneldefaultdata "spiceai_app" "existing" {
id = 12345
}data "spiceai_apps" "all" {}
# Filter in Terraform
locals {
prod_apps = [for app in data.spiceai_apps.all.apps : app if app.visibility == "private"]
}data "spiceai_members" "all" {}usernamerolesis_owneruser_iddata "spiceai_secrets" "app" {
app_id = spiceai_app.analytics.id
}# App (by app ID)
terraform import spiceai_app.analytics 12345
# Deployment (appId/deploymentId)
terraform import spiceai_deployment.current 12345/67890
# Secret (appId/SECRET_NAME)
terraform import spiceai_secret.db_password 12345/DB_PASSWORD
# Member (by user ID)
terraform import spiceai_member.alice 789
# Member with for_each
terraform import 'spiceai_member.team["alice"]' 789spiceai_secretvalueterraform {
required_providers {
spiceai = {
source = "spiceai/spiceai"
version = "~> 0.1"
}
}
}
provider "spiceai" {}
# Look up available regions and runtime versions
data "spiceai_regions" "available" {}
data "spiceai_container_images" "stable" {
channel = "stable"
}
# Create the app
resource "spiceai_app" "myapp" {
name = "my-analytics"
cname = data.spiceai_regions.available.default
image_tag = data.spiceai_container_images.stable.default
spicepod = yamlencode({
version = "v1"
kind = "Spicepod"
name = "my-analytics"
datasets = [{
from = "postgres:public.events"
name = "events"
params = {
pg_host = "db.example.com"
pg_user = "$${secrets:PG_USER}"
pg_pass = "$${secrets:PG_PASS}"
}
}]
models = [{
from = "openai:gpt-4o"
name = "assistant"
params = {
openai_api_key = "$${secrets:OPENAI_API_KEY}"
}
}]
})
}
# Manage secrets
variable "app_secrets" {
type = map(string)
sensitive = true
}
resource "spiceai_secret" "secrets" {
for_each = var.app_secrets
app_id = spiceai_app.myapp.id
name = each.key
value = each.value
}
# Deploy (redeploys when app config changes)
resource "spiceai_deployment" "current" {
app_id = spiceai_app.myapp.id
commit_message = "Managed by Terraform"
triggers = {
spicepod = spiceai_app.myapp.spicepod
image_tag = spiceai_app.myapp.image_tag
}
depends_on = [spiceai_secret.secrets]
}
# Team access
resource "spiceai_member" "team" {
for_each = toset(["alice", "bob"])
username = each.key
}
# Outputs
output "app_id" {
value = spiceai_app.myapp.id
}
output "api_key" {
value = spiceai_app.myapp.api_key
sensitive = true
}
output "deployment_status" {
value = spiceai_deployment.current.status
}data.spiceai_regionsdata.spiceai_container_imagesfor_eachsensitivetriggersdepends_on$${secrets:NAME}$| Issue | Solution |
|---|---|
| Verify |
| Import loses secret value | Expected — set |
Deployment stuck in | Check app has a valid |
| Previous deployment still in progress; wait or check status |
| Spicepod YAML syntax errors | Use |
| Use |
| Cannot delete org owner | Organization owners cannot be managed by Terraform; remove manually |
| Provider not found | Check |