Convention specification

Derived Developer Identity

A developer deployment names its instance from the Terraform workspace, chosen from an override, the CI branch, or the local username — never from a per-developer file.

Applies at
workspaces/
Status
Stable

01 Defines

How a single committed workspace root yields one isolated instance per developer or branch: the deployer selects a Terraform workspace from standard context, and the root derives every name from terraform.workspace.

02 Applies when

  • Several people or branches deploy their own copy of the same system from one root.
  • Instances need separate state, resources, and hostnames without separate configuration.
  • The same command runs both on a laptop and in CI.

03 Boundaries

  • Applies to workspaces/ roots only; canonical roots under env/ own their state directly and take no identity from context.
  • Derived identity names the instance; it does not change what the instance is built from.
  • Credentials are not derived this way; roots still use their committed provider profiles.

Expected behaviour

  1. 01
    The workspace name is the first of DEPLOY_WORKSPACE, GITHUB_REF_NAME, and id -un that is set.
  2. 02
    The deployer runs terraform workspace select -or-create, so a first deploy needs no setup step.
  3. 03
    The root uses terraform.workspace for every name that has to be unique, such as the hostname and tags.
  4. 04
    One committed backend key serves every instance; the S3 backend stores each workspace under env:/<workspace>/<key>.
  5. 05
    An instance is removed completely with make deploy.destroy.

Behaviour#

Every developer needs their own copy, but nobody wants a directory per developer. The convention resolves this by deriving identity from context that already exists. Locally that is your username; in CI it is the branch name; when you want more than one copy, it is whatever you set DEPLOY_WORKSPACE to.

The deployer turns that name into a Terraform workspace, and the root reads it back as terraform.workspace. From there, one value flows into the state path, the hostname, and the resource tags, so two instances can never collide.

FlowResolving an instance
  1. 01 Override DEPLOY_WORKSPACE if set — for a second copy of your own
  2. 02 Branch Otherwise GITHUB_REF_NAME, the branch name in CI
  3. 03 User Otherwise id -un, your local username
  4. 04 Select terraform workspace select -or-create <name> in workspaces/site
  5. 05 Derive State at env:/<name>/<key>, hostname sampletest-<name>.dev.prosyon.ca Workspaces

Why derive rather than configure#

Derived from convention

  • One root, reviewed once, used by everyone
  • A new developer deploys with no setup
  • Branch instances appear without extra files

Per-developer configuration

  • A directory or .tfvars file per person
  • Copies drift and pick up private changes
  • Local variable files tempt secrets into the tree

Canonical environments take the opposite position: nothing about them comes from context. See Parameterless Deployment .

Examples#

Only the workspace root selects a workspace; canonical roots skip this step:

scripts/deploy.sh
# workspaces/site deploys one instance per developer or branch, each with its own
# state and hostname. The canonical environments own their state directly.
if [ "$root" = workspaces/site ]; then
	terraform -chdir="$root" workspace select -or-create \
		"${DEPLOY_WORKSPACE:-${GITHUB_REF_NAME:-$(id -un)}}"
fi

One backend key is enough, because the S3 backend separates workspaces itself:

workspaces/site/backend.tf
# One backend, one state object per Terraform workspace: the S3 backend stores
# non-default workspaces under env:/<workspace>/<key>.
terraform {
  backend "s3" {
    bucket       = "org-terraform-state-220087710539"
    region       = "us-west-2"
    key          = "static-website/workspaces/site/terraform.tfstate"
    encrypt      = true
    use_lockfile = true
  }
}
make deploy                               # instance named after you
DEPLOY_WORKSPACE=experiment make deploy   # a second, separate instance