Skip to content
Infrastructure as Code iac workflow 5 min read

Resource Targeting

Resource targeting lets you narrow a terraform plan or terraform apply to a specific subset of your configuration using the -target flag. Instead of evaluating and reconciling every resource in the working directory, Terraform restricts its attention to the addresses you name plus their dependencies. This is a powerful surgical tool — but it is explicitly an escape hatch, not part of a healthy day-to-day workflow. Understanding when it helps and how it can quietly damage your state is the difference between a clean recovery and a deeper mess.

How -target works

When you pass -target=ADDRESS, Terraform builds a reduced dependency graph. It includes the targeted resource, everything that resource depends on (so it can compute its arguments correctly), and the providers required to manage them. Resources that are not in that subgraph are skipped entirely — they are neither refreshed, planned, nor changed.

The address you supply uses standard Terraform resource address syntax: a managed resource is type.name, a module call is module.name, and you can index into collections with [index] or ["key"].

# A single resource
terraform apply -target=aws_instance.web

# One instance from a count/for_each resource
terraform apply -target='aws_instance.web[0]'
terraform apply -target='aws_instance.web["us-east-1a"]'

# An entire module (all resources inside it)
terraform apply -target=module.networking

# A resource nested inside a module
terraform apply -target=module.networking.aws_subnet.private

You can repeat the flag to target several addresses at once. The -target flag works identically in OpenTofu, which mirrors Terraform’s CLI surface.

terraform apply -target=aws_instance.web -target=aws_eip.web

A worked example

Consider a small configuration with a security group, an instance, and an Elastic IP:

resource "aws_security_group" "web" {
  name        = "web-sg"
  description = "Allow HTTP"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami                    = "ami-0c02fb55956c7d316"
  instance_type          = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web.id]
}

resource "aws_eip" "web" {
  instance = aws_instance.web.id
  domain   = "vpc"
}

If you target only the instance, Terraform pulls in the security group because the instance depends on it, but it leaves the Elastic IP untouched:

terraform apply -target=aws_instance.web

Output:

aws_security_group.web: Refreshing state... [id=sg-0a1b2c3d4e5f]
aws_instance.web: Refreshing state... [id=i-09f8e7d6c5b4a]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_instance.web will be updated in-place
  ~ resource "aws_instance" "web" {
        id            = "i-09f8e7d6c5b4a"
      ~ instance_type = "t3.micro" -> "t3.small"
    }

Plan: 0 to add, 1 to change, 0 to destroy.


│ Warning: Resource targeting is in effect

│ You are creating a plan with the -target option, which means that the
│ result of this plan may not represent all of the changes requested by
│ the current configuration.

Note the warning: Terraform always tells you the plan is partial. The Elastic IP is absent from the plan even if its configuration drifted.

Legitimate use cases

Targeting exists for situations where applying the full configuration is impossible, unsafe, or unnecessarily slow.

Use caseWhy -target helps
Recovering from a failed applyA partial apply left some resources created and others not. Targeting the stuck resource lets you finish without re-planning everything.
Working around a provider bugA dependency cycle or buggy refresh blocks the full plan; targeting routes around the broken resource until a fix lands.
Breaking a chicken-and-egg bootstrapCreate a resource that another resource’s data source needs to read before that data source can be evaluated.
DebuggingIsolate one resource to see exactly what Terraform proposes for it, without noise from unrelated diffs.
Large, slow configurationsWhen you are certain only one resource changed, targeting avoids a long full refresh — though this should be temporary.

Why it is an escape hatch, not routine

The core risk is state divergence. Because non-targeted resources are skipped, your applied infrastructure can drift away from what the configuration as a whole describes. The next untargeted apply will then surface a pile of changes you forgot about — and those changes may interact in ways you did not intend.

Targeting also silently ignores dependents. If you target a resource and change an output other resources consume, those downstream resources are not updated until a later full apply, leaving a window of inconsistency.

Warning: Routine use of -target is a strong signal that your configuration should be split into smaller, independently managed root modules (separate state files). If you find yourself reaching for -target every day, refactor the layout rather than working around it.

Tip: After any targeted apply, run a plain terraform plan (no -target) as soon as it is safe. A clean “No changes” result confirms your real infrastructure matches the full configuration again.

For replacing a single resource — the most common reason people reach for targeting — prefer the dedicated -replace flag, which is purpose-built and does not bypass the rest of the plan:

terraform apply -replace=aws_instance.web

Best Practices

  • Treat -target as an exception you can justify in a sentence, not a default workflow.
  • Always run a full, untargeted terraform plan afterward to confirm the configuration and real state have converged.
  • Prefer -replace over -target when your actual goal is to recreate one resource.
  • If you target a module, remember every resource inside it (and its dependencies) is included — scope to the narrowest address that solves the problem.
  • Quote addresses containing [, ], or " so your shell does not mangle them.
  • When targeting becomes habitual, split the configuration into smaller root modules with their own state instead.
  • Capture the warning banner in code review or CI logs so partial applies are never invisible to your team.
Last updated June 14, 2026
Was this helpful?