This guide explains how Pulumi Any Terraform works internally, how the bridge operates, and the technical design decisions behind the project.
Overview#
Pulumi Any Terraform is a dynamic bridge that automatically converts Terraform providers into native Pulumi providers. This is achieved through Pulumi's pulumi-terraform-bridge, which translates Terraform's schema and resources into Pulumi's type system.
How It Works#
The Bridge Process#
-
Terraform Provider Schema: Each Terraform provider defines its resources, data sources, and configuration in Go code with schemas.
-
Bridge Configuration: The bridge reads the provider's schema and generates corresponding Pulumi resources.
-
Type Generation: TypeScript type definitions are automatically generated, providing full IntelliSense and type safety.
-
Resource Mapping: Terraform resources are mapped to Pulumi custom resources with appropriate CRUD operations.
-
Runtime Execution: When you run
pulumi up, the Pulumi engine invokes the bridged provider, which in turn calls the original Terraform provider.
Project Structure#
Provider Package Structure#
Each provider package follows a consistent structure:
Key Components#
1. Provider Resource#
Each package exports a Provider resource that configures the Terraform provider:
2. Custom Resources#
Resources are wrapped as Pulumi CustomResource classes with:
- Full TypeScript types
- Input/output properties
- Proper lifecycle management
- State tracking
3. Type Definitions#
All inputs and outputs are strongly typed:
Parameterization#
Each provider uses parameterization to specify which Terraform provider to bridge. This is stored as a base64-encoded value in package.json:
Decoded, this specifies:
This tells Pulumi:
- Which Terraform provider to use (
namecheap/namecheap) - Which version to bridge (
2.2.0) - Where to download it from (
registry.opentofu.org)
Build System#
The project uses Nx for monorepo management and build orchestration:
Nx Workspace#
Build Plugins#
Custom Nx plugins in /tools/ provide:
- Build Plugin (
build.ts): TypeScript compilation orchestration - Linter Plugin (
linter.ts): Code quality checks - Oxfmt Plugin (
oxfmt.ts): Code formatting - Syncpack Plugin (
syncpack.ts): Dependency synchronization - Audit Plugin (
audit.ts): Security vulnerability scanning
Caching#
Nx provides smart caching to speed up builds:
- Local cache: Stores build outputs locally
- Computation caching: Skips unnecessary rebuilds
CI/CD Pipeline#
Workflow Architecture#
Key Workflows#
1. Test Workflow (test.yml)#
- Runs on every push and PR
- Lints code with Biome
- Builds all packages
- Runs type checking
- Uses Nx affected commands for efficiency
2. Update Workflow (update.yml)#
- Runs daily or on-demand
- Checks for dependency updates
- Creates automated PRs
- Uses Renovate for dependency management
3. Publish Workflow (publish.yml)#
- Runs on main branch after successful tests
- Uses Changesets for version management
- Publishes packages to NPM
- Creates release notes automatically
External Integrations#
1. Terraform Registry#
- Purpose: Source for Terraform providers
- Usage: Downloads provider schemas and binaries
- URL:
registry.terraform.ioandregistry.opentofu.org
2. NPM Registry#
- Purpose: Distribution of Pulumi packages
- Usage: Publishing and installing packages
- Packages: All under
pulumi-*namespace
3. GitHub#
- Purpose: Source control and CI/CD
- Features:
- Issue tracking
- Pull requests
- GitHub Actions
- Package registry
4. Aikido Safe Chain#
- Purpose: Dependency security scanning
- Usage: Blocks malicious packages during install
- Integration: GitHub Actions
5. Autofix.ci#
- Purpose: Automated code fixes
- Usage: Auto-fixes linting and formatting issues
- Integration: Automatic PR commits
State Management#
Pulumi manages state differently from Terraform:
Pulumi State#
- Stored in Pulumi Service (default) or self-managed backend
- Contains resource metadata and outputs
- Supports encryption and access control
- Enables collaboration and history tracking
Bridge State Translation#
The bridge translates between Pulumi and Terraform state:
- Pulumi tracks resources in its own state
- Bridge invokes Terraform provider with translated inputs
- Provider returns outputs
- Bridge translates back to Pulumi format
- Pulumi updates its state
Type Safety#
One of the main benefits of this bridge is complete type safety:
Input Types#
Output Types#
Type Inference#
Resource Lifecycle#
Resources follow Pulumi's standard lifecycle:
-
Create: When resource doesn't exist
- Bridge calls Terraform's Create method
- Returns resource ID and properties
-
Read: To refresh state
- Bridge calls Terraform's Read method
- Updates Pulumi state with current values
-
Update: When properties change
- Bridge calls Terraform's Update method
- Handles partial updates if supported
-
Delete: When resource is removed
- Bridge calls Terraform's Delete method
- Removes from Pulumi state
Performance Considerations#
Build Performance#
- Parallel compilation: Multiple packages build simultaneously
- Incremental builds: Only rebuild changed packages
- Caching: Skip unchanged builds entirely
- Nx affected: Only process affected packages
Runtime Performance#
- Lazy loading: Resources loaded on-demand
- Concurrent operations: Multiple resources created in parallel
- State optimization: Minimal state queries
- Provider reuse: Single provider instance per program
Security#
Dependency Security#
- Aikido Safe Chain: Scans npm packages during install
- Dependabot/Renovate: Automated security updates
- Audit checks: Regular security audits
Secrets Management#
- Pulumi secrets: Encrypted at rest and in transit
- Environment variables: For local development
- Config encryption: Sensitive config encrypted in state
Package Publishing#
- NPM 2FA: Required for publishing
- Provenance: Supply chain security
- Automated publishing: Reduces human error
Debugging#
Enable Debug Logging#
Inspect Bridge Behavior#
Future Enhancements#
Potential improvements to the architecture:
- Dynamic provider generation: Generate providers on-demand
- Better error messages: More helpful error context
- Performance optimization: Faster bridge overhead
- Multi-version support: Support multiple Terraform versions
- Enhanced types: More precise TypeScript types