Architecture specification

Workspaces

Developer-oriented deployment roots under workspaces/ whose instance identity may come from the current user or branch, kept apart from canonical environments.

Applies at
workspaces/
Status
Stable
Source · managed
workspaces/README.md

01 Defines

The directory of non-canonical deployment entry points — local, sandbox, and user-derived systems — that compose the same modules as env/ but may depend on developer context to name the instance.

02 Applies when

  • Developers need their own deployed copy of a system to test or validate changes.
  • A branch or pull request needs an isolated instance that does not touch shared environments.
  • Instance identity can reasonably come from the user, the branch, or a local override.

03 Boundaries

  • Canonical continuous-deployment targets stay in env/.
  • Reusable infrastructure stays in modules, local or external.
  • Workspaces never weaken the parameterless rules of env/; they exist so those rules can stay strict.

Expected behaviour

  1. 01
    Roots are organised by logical system or workflow, never by developer.
  2. 02
    Developer-specific identity is derived from standard conventions rather than per-developer files.
  3. 03
    Every root is readable, repeatable, and safe to destroy or recreate.
  4. 04
    Provider lock files are committed for deployable Terraform workspace roots.
  5. 05
    State files, local variable files, provider plugin directories, and cache output are never committed.

Behaviour#

env/ holds the deployments that matter to everyone. workspaces/ holds the ones that matter to a single person or branch for a while. Both compose the same reusable modules, so a developer’s copy is built the same way production is; the difference is how the instance is named and who owns it.

A workspace root is still committed, reviewed configuration. What it adds is permission to depend on context: the Terraform workspace, the current user, a branch name, an environment variable. That context decides the instance’s identity — its hostname, its state, its resources — and nothing else.

FlowOne root, many instances
  1. 01 Root workspaces/site/ — one committed definition for the whole team
  2. 02 Identity Terraform workspace from DEPLOY_WORKSPACE, the branch, or the username Derived Developer Identity
  3. 03 Instance Own state, bucket, distribution, certificate, and hostname
  4. 04 Destroy make deploy.destroy removes the instance entirely

Why not a directory per developer#

A directory per person drifts: each copy picks up its own tweaks, and the repository fills with roots nobody else understands. One root per system with identity derived at run time keeps a single definition, gives everyone the same behaviour, and still separates their resources completely.

Layout#

  • workspaces/
  • site/ A developer's own copy of the website Derived Developer Identity
  • .terraform.lock.hcl Committed provider lock file
  • backend.tf One backend; state per Terraform workspace
  • main.tf Hostname and tags from terraform.workspace Modules
  • outputs.tf Bucket, distribution, and URL for the deployer
  • providers.tf Named AWS profiles
  • versions.tf Terraform and provider constraints

Examples#

The workspace name flows straight into the hostname and the tags, so instances never collide:

workspaces/site/main.tf
# A developer's own copy of the site.
#
# The Terraform workspace names the instance, so each developer and each branch
# gets its own bucket, distribution, certificate, and hostname from the same
# committed configuration. scripts/deploy.sh selects the workspace.

locals {
  site_domain = "sampletest-${terraform.workspace}.dev.prosyon.ca"

  tags = {
    Environment = "workspace"
    Project     = "static-website"
    ManagedBy   = "terraform"
    Workspace   = terraform.workspace
  }
}

workspace is the default deployment target, so a bare command can only touch your own copy:

make deploy           # your own instance
make deploy.plan      # preview, changes nothing
make deploy.destroy   # tear it down