How to Create a Terraform Archive File for Deployment: A Complete Guide

The most effective method for creating a terraform archive file is using terraform plan -out=plan.zip, which internally invokes the planfile.Create function to bundle the plan, state files, configuration snapshot, and lock file into a single zip archive.

A terraform archive file serves as the deployment artifact in Terraform's remote execution workflow, encapsulating everything needed to apply infrastructure changes without access to the original configuration source. This article examines the implementation in the hashicorp/terraform repository to explain how these archives are structured, generated, and used in production deployment pipelines.

What Is a Terraform Archive File?

A terraform archive file is a zip archive that contains the complete context required to execute a plan remotely. According to the source code in internal/plans/planfile/writer.go, the archive bundles five critical components:

  • Serialized plan (tfplan): The binary plan output containing the proposed resource changes
  • Current state (tfstate): The latest Terraform state file after refresh operations
  • Previous state (tfstate-prev): The state file from before the last apply operation
  • Configuration snapshot: A complete copy of the .terraform module tree and configuration files stored under a virtual tfconfig/ directory
  • Dependency lock file (dependency-locks.hcl): The .terraform.lock.hcl content when present, ensuring consistent provider versions

How Terraform Creates Archive Files Internally

The archive creation process centers on the planfile.Create function located in internal/plans/planfile/writer.go. This function is invoked by the CLI when executing terraform plan -out=<filename> and by remote backends when preparing deployment artifacts.

The Archive Creation Process in writer.go

The planfile.Create function executes a precise sequence of operations to construct the zip archive:

  1. Open output file (line 55): Uses os.Create to open or truncate the target archive file
  2. Initialize zip writer (line 61): Wraps the file handle with zip.NewWriter to begin zip entry construction
  3. Write plan binary (lines 66-74): Serializes the plans.Plan object into a tfplan entry using Deflate compression
  4. Embed current state (lines 80-92): Calls statefile.Write to store the refreshed state as tfstate
  5. Embed previous state (lines 96-108): Stores the prior run state as tfstate-prev using the same method
  6. Snapshot configuration (lines 112-119): Walks the configuration directory and stores each file under the virtual tfconfig/ path
  7. Include lock file (lines 120-138): If DependencyLocks is provided, writes the content as dependency-locks.hcl
  8. Finalize archive (line 141): Closes the zip writer to flush all entries and complete the archive

Backend Integration

The archive creation is triggered from backend implementations after a successful plan operation. In internal/backend/local/backend_plan.go at line 187, the local backend invokes planfile.Create to persist the plan and its associated context to disk:

// From internal/backend/local/backend_plan.go
if err := planfile.Create(planOutPath, planfile.CreateArgs{
    ConfigSnapshot:       configSnapshot,
    PreviousRunStateFile: previousStateFile,
    StateFile:            stateFile,
    Plan:                 plan,
    DependencyLocks:      dependencyLocks,
}); err != nil {
    // Handle error
}

Creating a Terraform Archive File: CLI Method

For standard deployment workflows, use the Terraform CLI to generate the archive automatically. This method ensures all components are correctly serialized and compressed according to the internal specification.


# Create a plan and save it as a zip archive

terraform plan -out=deployment-plan.zip

# Apply the archived plan on a remote executor or different machine

terraform apply deployment-plan.zip

When you specify the -out flag, Terraform executes the full plan workflow, then calls planfile.Create to bundle the resulting plan with the current state, configuration snapshot, and lock file into the specified zip archive.

Creating a Terraform Archive File Programmatically

For custom tooling or CI/CD pipelines that need to generate archives without invoking the CLI directly, use the internal planfile package. This approach requires importing the Terraform internal packages and constructing the CreateArgs struct with properly initialized objects.

package main

import (
	"log"

	"github.com/hashicorp/terraform/internal/configs/configload"
	"github.com/hashicorp/terraform/internal/depsfile"
	"github.com/hashicorp/terraform/internal/plans"
	"github.com/hashicorp/terraform/internal/plans/planfile"
	"github.com/hashicorp/terraform/internal/states/statefile"
)

func main() {
	// These objects would be populated from your Terraform workflow:
	var cfgSnap *configload.Snapshot   // Configuration snapshot
	var prevState *statefile.File      // Previous run state
	var curState *statefile.File       // Current refreshed state
	var tfPlan *plans.Plan             // The computed plan
	var locks *depsfile.Locks          // Dependency locks (optional)

	args := planfile.CreateArgs{
		ConfigSnapshot:       cfgSnap,
		PreviousRunStateFile: prevState,
		StateFile:            curState,
		Plan:                 tfPlan,
		DependencyLocks:      locks,
	}

	// Create the archive at the specified path
	if err := planfile.Create("deployment-plan.zip", args); err != nil {
		log.Fatalf("failed to create terraform archive file: %v", err)
	}
}

Important considerations for programmatic use:

  • Import paths use github.com/hashicorp/terraform/internal/... which are internal packages subject to change between releases
  • The ConfigSnapshot must contain the complete module tree and configuration files
  • State files must be properly formatted *statefile.File objects, not raw JSON
  • Dependency locks ensure provider version consistency across execution environments

Key Source Files for Terraform Archive Creation

Understanding the implementation requires examining these specific files in the hashicorp/terraform repository:

File Purpose
internal/plans/planfile/writer.go Core implementation of planfile.Create that constructs the zip archive with all components
internal/backend/local/backend_plan.go Local backend that invokes planfile.Create at line 187 after plan execution
internal/plans/planfile/reader.go Counterpart that reads and validates the archive on the remote execution side
internal/terraform/context_test.go Test suite validating archive creation and extraction workflows
internal/command/command_test.go Integration tests ensuring the CLI properly generates archive files

Summary

  • A terraform archive file is a zip bundle containing the plan binary, current and previous state files, configuration snapshot, and dependency locks required for remote execution.
  • The most effective creation method is the CLI command terraform plan -out=plan.zip, which internally calls planfile.Create in internal/plans/planfile/writer.go.
  • For programmatic generation, import the internal planfile package and populate CreateArgs with configuration snapshots, state files, and plan objects.
  • The archive format uses standard zip compression with specific entry names (tfplan, tfstate, tfconfig/, etc.) that the reader implementation expects in internal/plans/planfile/reader.go.

Frequently Asked Questions

What exactly is inside a terraform archive file?

A terraform archive file contains five essential components: the serialized plan binary (tfplan), the current state file (tfstate), the previous state file (tfstate-prev), a complete snapshot of your configuration stored under tfconfig/, and optionally the dependency lock file (dependency-locks.hcl). These components are bundled by the planfile.Create function in internal/plans/planfile/writer.go to ensure the remote executor has everything needed to apply the plan without access to your source repository.

Can I create a terraform archive file without using the CLI?

Yes, you can create a terraform archive file programmatically by importing the internal github.com/hashicorp/terraform/internal/plans/planfile package and calling planfile.Create with a populated CreateArgs struct. This approach requires constructing configuration snapshots, state file objects, and plan structures manually, which is typically only done when building custom CI/CD tooling. Note that internal packages are subject to breaking changes between Terraform releases.

How does Terraform Cloud use the archive file?

When you run terraform plan -out=plan.zip and configure a remote backend like Terraform Cloud, the CLI automatically uploads the archive file to the remote executor. The server-side implementation uses internal/plans/planfile/reader.go to extract the plan, state, and configuration snapshot from the zip entries. This allows the remote agent to apply the plan in a secure, isolated environment without requiring access to your local configuration files or state storage.

What compression method does Terraform use for archive files?

Terraform uses standard Deflate compression for the zip archive entries, specifically when writing the tfplan binary in internal/plans/planfile/writer.go (lines 66-74). The implementation uses Go's standard archive/zip package with zip.Deflate as the compression method. State files and configuration snapshots are also stored within the same zip container, though the specific compression settings may vary by entry type based on the writer implementation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →