Introducción

Hasta ahora hemos trabajado con configuraciones de Terraform que gestionan un único entorno. Sin embargo, en proyectos reales es común necesitar desplegar la misma infraestructura en múltiples entornos: desarrollo, pruebas, staging y producción. Terraform ofrece una funcionalidad llamada workspaces (espacios de trabajo) que permite gestionar múltiples estados independientes desde una misma configuración de código.

En esta lección aprenderás qué son los workspaces, cómo se utilizan, cuándo son apropiados y cuándo debes considerar alternativas.


  1. ¿Qué son los Workspaces en Terraform?

Un workspace en Terraform es un entorno de estado aislado dentro de un mismo directorio de configuración. Cada workspace mantiene su propio archivo de estado (terraform.tfstate), lo que permite que los mismos archivos .tf gestionen recursos completamente independientes.

Por defecto, Terraform siempre trabaja en un workspace llamado default. Cuando creas workspaces adicionales, Terraform guarda sus estados en subcarpetas dentro de terraform.tfstate.d/.

¿Por qué son útiles?

  • Reutilización de código: Un mismo conjunto de archivos .tf puede gestionar infraestructura en distintos entornos sin duplicar código.
  • Aislamiento de estado: Los recursos de dev y prod no comparten estado, por lo que un error en dev no afecta a prod.
  • Simplicidad: No es necesario mantener múltiples repositorios o directorios para cada entorno cuando las diferencias son mínimas.

  1. El Workspace Default y Workspaces Adicionales

Cuando inicializas un proyecto Terraform por primera vez, automáticamente se encuentra en el workspace default. Este workspace es especial: no puede eliminarse.

# Comprobamos en qué workspace estamos actualmente
terraform workspace show
# Salida: default

Los workspaces adicionales son entornos completamente separados que puedes crear para tus distintos entornos. Por ejemplo:

  • default — podría usarse para producción o simplemente como estado base
  • dev — entorno de desarrollo
  • staging — entorno de pruebas previas a producción
  • prod — entorno de producción (si no se usa default)

Estructura de archivos en disco

mi-proyecto/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfstate          ← Estado del workspace "default"
└── terraform.tfstate.d/
    ├── dev/
    │   └── terraform.tfstate  ← Estado del workspace "dev"
    └── staging/
        └── terraform.tfstate  ← Estado del workspace "staging"

Cada directorio dentro de terraform.tfstate.d/ contiene el estado exclusivo de ese workspace, completamente aislado de los demás.


  1. Comandos de Workspace

Terraform proporciona un subcomando workspace con varias operaciones. Veamos cada una:

terraform workspace list

Lista todos los workspaces existentes. El workspace activo se marca con un asterisco (*).

terraform workspace list
# Salida:
#   default
# * dev
#   staging

terraform workspace new

Crea un nuevo workspace y lo selecciona automáticamente como workspace activo.

terraform workspace new dev
# Salida: Created and switched to workspace "dev"!
# You're now on a new, empty workspace. Terraform operations will
# now operate on this new workspace.

Importante: Al crear un workspace nuevo, el estado está vacío. Terraform no copia los recursos del workspace anterior.

terraform workspace select

Cambia al workspace especificado sin crear uno nuevo.

terraform workspace select prod
# Salida: Switched to workspace "prod".

terraform workspace show

Muestra el nombre del workspace actualmente activo.

terraform workspace show
# Salida: prod

terraform workspace delete

Elimina un workspace. Solo se puede eliminar si el workspace no tiene recursos en su estado (estado vacío) y si no es el workspace default.

# Primero destruimos los recursos del workspace
terraform workspace select staging
terraform destroy

# Luego cambiamos a otro workspace y eliminamos el vacío
terraform workspace select default
terraform workspace delete staging
# Salida: Deleted workspace "staging"!

  1. La Variable terraform.workspace

Dentro de tu código HCL puedes acceder al nombre del workspace activo mediante la variable especial terraform.workspace. Esto es fundamental para diferenciar configuraciones entre entornos.

Uso básico

# main.tf

resource "aws_instance" "web" {
  # La AMI varía según el entorno
  ami           = var.ami_id
  instance_type = terraform.workspace == "prod" ? "t3.large" : "t3.micro"
  # Si estamos en producción usamos t3.large, en cualquier otro entorno t3.micro

  tags = {
    Name        = "web-${terraform.workspace}"
    # El nombre incluye el workspace: "web-dev", "web-prod", etc.
    Environment = terraform.workspace
    # Etiqueta para identificar fácilmente el entorno
  }
}

Uso con locals para mayor organización

Una práctica muy recomendada es usar locals para centralizar las configuraciones por entorno:

# locals.tf

locals {
  # Mapa con configuraciones específicas por entorno
  env_config = {
    dev = {
      instance_type  = "t3.micro"    # Instancia pequeña para dev
      instance_count = 1             # Solo una instancia
      db_size        = "db.t3.micro" # Base de datos pequeña
      enable_backups = false         # Sin backups en dev para ahorrar costes
    }
    staging = {
      instance_type  = "t3.small"   # Instancia media para staging
      instance_count = 2            # Dos instancias para simular producción
      db_size        = "db.t3.small"
      enable_backups = false
    }
    prod = {
      instance_type  = "t3.large"   # Instancia grande para producción
      instance_count = 3            # Tres instancias para alta disponibilidad
      db_size        = "db.t3.medium"
      enable_backups = true         # Backups habilitados en producción
    }
  }

  # Seleccionamos la configuración del workspace activo
  # Si el workspace no existe en el mapa, usamos "dev" como fallback
  current_config = local.env_config[terraform.workspace]
}

  1. Ejemplo Completo: Infraestructura Multi-Entorno con Workspaces

Veamos un ejemplo completo y realista que usa workspaces para desplegar una aplicación web en diferentes entornos:

# variables.tf

variable "region" {
  description = "Región de AWS donde desplegar los recursos"
  type        = string
  default     = "eu-west-1"
}

variable "project_name" {
  description = "Nombre del proyecto, usado como prefijo en los recursos"
  type        = string
  default     = "myapp"
}
# locals.tf

locals {
  # Configuraciones específicas por entorno
  workspace_config = {
    dev = {
      instance_type       = "t3.micro"
      min_size            = 1
      max_size            = 2
      desired_capacity    = 1
      deletion_protection = false  # Permite eliminar la BD fácilmente en dev
      multi_az            = false  # Sin alta disponibilidad en dev
    }
    staging = {
      instance_type       = "t3.small"
      min_size            = 1
      max_size            = 3
      desired_capacity    = 2
      deletion_protection = false
      multi_az            = false
    }
    prod = {
      instance_type       = "t3.large"
      min_size            = 2
      max_size            = 10
      desired_capacity    = 3
      deletion_protection = true   # Protección contra eliminación accidental
      multi_az            = true   # Alta disponibilidad en producción
    }
  }

  # Accedemos a la configuración del workspace actual
  config = local.workspace_config[terraform.workspace]

  # Tags comunes aplicados a todos los recursos
  common_tags = {
    Project     = var.project_name
    Environment = terraform.workspace   # "dev", "staging" o "prod"
    ManagedBy   = "Terraform"
    Workspace   = terraform.workspace
  }
}
# main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = var.region
}

# VPC específica para cada entorno
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = merge(local.common_tags, {
    Name = "${var.project_name}-${terraform.workspace}-vpc"
    # Nombre descriptivo que incluye proyecto y entorno
  })
}

# Grupo de Auto Scaling con configuración según entorno
resource "aws_autoscaling_group" "web" {
  # Usamos la configuración del workspace actual
  min_size         = local.config.min_size
  max_size         = local.config.max_size
  desired_capacity = local.config.desired_capacity

  # Otros parámetros...

  tag {
    key                 = "Name"
    value               = "${var.project_name}-${terraform.workspace}-web"
    propagate_at_launch = true
    # Este tag se propagará a cada instancia EC2 que se cree
  }
}
# outputs.tf

output "environment" {
  description = "Entorno activo (workspace)"
  value       = terraform.workspace
  # Nos confirma en qué entorno hemos aplicado los cambios
}

output "vpc_id" {
  description = "ID de la VPC creada para este entorno"
  value       = aws_vpc.main.id
}

Flujo de trabajo con workspaces

# 1. Inicializamos el proyecto
terraform init

# 2. Creamos y activamos el workspace de desarrollo
terraform workspace new dev

# 3. Planificamos y aplicamos en dev
terraform plan
terraform apply

# 4. Cambiamos al workspace de staging
terraform workspace new staging
# El estado está vacío: los recursos de dev no aparecen aquí

# 5. Aplicamos la misma configuración en staging
terraform apply
# Se crean nuevos recursos independientes para staging

# 6. Finalmente, trabajamos en producción
terraform workspace new prod
terraform apply

  1. Limitaciones de los Workspaces Locales

Los workspaces locales tienen importantes limitaciones que debes conocer:

  • Los estados se guardan localmente: Si trabajas en equipo, cada miembro tendría sus propios estados, lo que puede causar conflictos. Para equipos, es necesario usar remote state (S3, Terraform Cloud, etc.).
  • No hay aislamiento de backend por defecto: Todos los workspaces comparten la misma configuración de backend.
  • No se escalan bien con muchos entornos: Si tienes 10+ entornos con configuraciones muy distintas, los workspaces se vuelven difíciles de gestionar.
  • Sin variables de entorno automáticas: Terraform no carga automáticamente archivos .tfvars distintos por workspace; tienes que hacerlo manualmente.

  1. Diferencia entre Workspaces y Directorios Separados

Muchos equipos optan por usar directorios separados en lugar de workspaces. ¿Cuál es la diferencia?

Directorios separados

infrastructure/
├── dev/
│   ├── main.tf
│   ├── variables.tf
│   └── terraform.tfvars
├── staging/
│   ├── main.tf
│   ├── variables.tf
│   └── terraform.tfvars
└── prod/
    ├── main.tf
    ├── variables.tf
    └── terraform.tfvars

Cada directorio tiene su propia configuración completa. Los cambios se aplican entrando al directorio correspondiente.

Workspaces

infrastructure/
├── main.tf         ← Un solo archivo compartido
├── variables.tf
└── locals.tf       ← Configuración centralizada por entorno

  1. Tabla Comparativa: Workspaces vs Directorios vs Módulos

Característica Workspaces Directorios Separados Módulos Reutilizables
Reutilización de código Alta (un solo código) Baja (código duplicado) Muy alta (módulos reutilizados)
Aislamiento Por estado Total (código y estado) Depende de la implementación
Complejidad inicial Baja Media Alta
Diferencias entre entornos Solo mediante variables/locals Pueden ser totalmente distintos Configurables mediante variables
Riesgo de afectar producción Medio (mismo código) Bajo (código separado) Bajo si se versiona correctamente
Escalabilidad Media (muchos workspaces = complejidad) Alta Muy alta
Recomendado para Entornos muy similares Entornos con muchas diferencias Infraestructura compleja y reusable
Gestión de equipo Requiere remote state Más sencillo Requiere planificación

  1. Cuándo Usar Workspaces y Cuándo No

Usa workspaces cuando:

  • Los entornos tienen configuraciones muy similares (solo cambian tamaños o contadores)
  • Quieres desplegar rápidamente un entorno idéntico al actual
  • El equipo es pequeño y trabajáis coordinadamente
  • Usas remote state (Terraform Cloud, S3+DynamoDB)

Evita workspaces cuando:

  • Los entornos tienen configuraciones radicalmente distintas
  • Necesitas que diferentes personas tengan permisos sobre diferentes entornos
  • Las diferencias son tan grandes que el código con condicionales se vuelve ilegible
  • Trabajas con infraestructura crítica de producción que requiere máximo aislamiento

Consejo de HashiCorp: La propia documentación oficial de Terraform recomienda usar directorios separados para entornos de producción, reservando los workspaces para pruebas rápidas o entornos efímeros.


  1. Ejercicio Práctico

Objetivo

Crear dos workspaces (dev y prod) que desplieguen un archivo de texto local con diferentes contenidos según el entorno, usando el provider local de Terraform (sin necesidad de credenciales de nube).

Instrucciones

  1. Crea un directorio llamado workspace-lab/
  2. Dentro, crea los siguientes archivos
  3. Crea ambos workspaces y aplica la configuración en cada uno
  4. Verifica que los archivos generados son diferentes

Solución Detallada

# workspace-lab/main.tf

terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      # El provider "local" permite gestionar archivos en el sistema de archivos
      version = "~> 2.0"
    }
  }
}

locals {
  # Configuraciones por entorno
  env_settings = {
    dev = {
      message      = "¡Bienvenido al entorno de DESARROLLO!"
      debug_mode   = true
      log_level    = "DEBUG"
      replicas     = 1
      feature_flag = "experimental_features=ON"
    }
    prod = {
      message      = "Entorno de PRODUCCIÓN - Proceder con cuidado"
      debug_mode   = false
      log_level    = "ERROR"
      replicas     = 3
      feature_flag = "experimental_features=OFF"
    }
  }

  # Seleccionamos la configuración del workspace actual
  # Si no hay configuración para el workspace, usamos "dev" por defecto
  settings = lookup(local.env_settings, terraform.workspace, local.env_settings["dev"])
}

# Creamos un archivo de configuración de la aplicación
resource "local_file" "app_config" {
  filename = "${path.module}/output/app-config-${terraform.workspace}.txt"
  # El nombre del archivo incluye el workspace para distinguirlos

  content = <<-EOT
    # Configuración de la Aplicación
    # Generada automáticamente por Terraform
    # Entorno: ${terraform.workspace}
    # Fecha: generado por Terraform

    ENVIRONMENT=${terraform.workspace}
    MESSAGE=${local.settings.message}
    DEBUG_MODE=${local.settings.debug_mode}
    LOG_LEVEL=${local.settings.log_level}
    REPLICAS=${local.settings.replicas}
    ${local.settings.feature_flag}
  EOT
  # EOT marca el fin del bloque heredoc (texto multilínea)
}

# Creamos un archivo de resumen
resource "local_file" "summary" {
  filename = "${path.module}/output/summary-${terraform.workspace}.json"

  content = jsonencode({
    # jsonencode convierte el objeto HCL a formato JSON
    workspace   = terraform.workspace
    environment = terraform.workspace
    config      = local.settings
    # Incluimos toda la configuración en formato JSON
  })
}
# workspace-lab/outputs.tf

output "workspace_name" {
  description = "Nombre del workspace activo"
  value       = terraform.workspace
}

output "config_file_path" {
  description = "Ruta del archivo de configuración generado"
  value       = local_file.app_config.filename
}

output "applied_settings" {
  description = "Configuración aplicada en este entorno"
  value       = local.settings
}

Pasos para ejecutar el ejercicio

# 1. Creamos el directorio de salida
mkdir -p workspace-lab/output

# 2. Entramos al directorio del ejercicio
cd workspace-lab

# 3. Inicializamos Terraform
terraform init
# Descarga el provider "local"

# 4. Verificamos que estamos en el workspace default
terraform workspace show
# Salida: default

# 5. Creamos el workspace de desarrollo
terraform workspace new dev
# Salida: Created and switched to workspace "dev"!

# 6. Aplicamos en dev (sin necesidad de confirmar con -auto-approve en producción real)
terraform apply -auto-approve
# Crea output/app-config-dev.txt y output/summary-dev.json

# 7. Vemos el output
terraform output applied_settings
# Muestra la configuración de dev: debug=true, replicas=1, etc.

# 8. Cambiamos a workspace de producción
terraform workspace new prod

# 9. Aplicamos en prod
terraform apply -auto-approve
# Crea output/app-config-prod.txt y output/summary-prod.json

# 10. Listamos todos los workspaces
terraform workspace list
#   default
#   dev
# * prod

# 11. Verificamos los archivos generados
cat output/app-config-dev.txt
cat output/app-config-prod.txt
# Los archivos tienen contenido diferente según el entorno

  1. Errores Comunes con Workspaces

Error 1: Olvidar seleccionar el workspace correcto

# Problema: Aplicar cambios en el workspace equivocado
terraform workspace show
# Salida: dev   ← Deberíamos estar en prod

# Consecuencia: Se crean/modifican recursos en dev cuando queríamos prod

# Solución: Siempre verificar el workspace antes de apply
terraform workspace show && terraform plan

Error 2: Workspace no definido en el mapa de configuración

# Problema: Si accedemos directamente al mapa y el workspace no existe
locals {
  config = local.env_config[terraform.workspace]
  # Si terraform.workspace = "test" y "test" no está en env_config,
  # Terraform lanzará un error de índice
}

# Solución: Usar lookup() con valor por defecto
locals {
  config = lookup(local.env_config, terraform.workspace, local.env_config["dev"])
  # Si el workspace no existe en el mapa, usa la configuración de "dev"
}

Error 3: Intentar eliminar el workspace default

terraform workspace delete default
# Error: default workspace cannot be deleted
# El workspace "default" es especial y no puede eliminarse

Error 4: Eliminar un workspace con recursos activos

terraform workspace select staging
terraform workspace delete staging
# Error: workspace is not empty
# Debes destruir los recursos antes de eliminar el workspace

# Solución correcta:
terraform destroy  # Destruye los recursos del workspace actual
terraform workspace select default
terraform workspace delete staging  # Ahora funciona

Error 5: Confundir workspaces con branches de Git

Los workspaces de Terraform son independientes de las ramas de Git. Puedes estar en la rama main de Git y en el workspace dev de Terraform al mismo tiempo. Estos son sistemas completamente independientes.


Resumen

En esta lección hemos aprendido:

  • Los workspaces permiten gestionar múltiples entornos desde un mismo código Terraform, manteniendo estados separados e independientes.
  • El workspace default existe siempre y no puede eliminarse.
  • Con terraform.workspace podemos acceder al nombre del workspace activo dentro del código HCL para adaptar la configuración.
  • Los workspaces son ideales para entornos muy similares con pocas diferencias de configuración.
  • Para entornos con grandes diferencias o equipos grandes, los directorios separados suelen ser más apropiados.
  • Siempre verifica en qué workspace estás antes de ejecutar terraform apply.

En la siguiente lección exploraremos las funciones de Terraform, que nos permitirán transformar y manipular datos dentro de nuestras configuraciones de forma elegante y poderosa.

© Copyright 2026. Todos los derechos reservados