Frequently Asked Questions (FAQ)¶
Common questions and answers about Pyvider.
General Questions¶
What is Pyvider?¶
Pyvider is a Python framework for building Terraform providers. It implements the Terraform Plugin Protocol v6, allowing you to create infrastructure providers using pure Python instead of Go.
Why use Pyvider instead of the Go SDK?¶
Use Pyvider when: - You're more comfortable with Python than Go - You want to leverage Python's rich ecosystem (httpx, pydantic, etc.) - Your team already has Python expertise - You're building internal tooling or prototypes - You prefer Python's async/await over Go's goroutines
Use Go SDK when: - You need absolute maximum performance - You're building a high-traffic public provider - Your team has Go expertise - You want the most mature, battle-tested framework
Is Pyvider production-ready?¶
Pyvider is currently in alpha (v0.0.x). While it implements the full Terraform Plugin Protocol v6 and is well-tested, APIs may change before 1.0. It's best suited for:
- Internal tooling and automation
- Rapid prototyping
- Learning and experimentation
- Custom providers for specific needs
See the Roadmap for the path to 1.0.
What Python version is required?¶
Python 3.11 or higher is required. Pyvider uses modern Python features like:
- Native async/await
- Type hints and | union syntax
- Structured pattern matching (in some areas)
Can I use existing Python libraries?¶
Yes! One of Pyvider's main benefits is access to Python's ecosystem: - HTTP clients: httpx, aiohttp - Cloud SDKs: boto3, azure-sdk, google-cloud - Data: pandas, polars - Utilities: arrow (dates), pydantic (validation)
Just ensure they support async/await if you're using them in async contexts.
Architecture Questions¶
How does Pyvider work?¶
Pyvider acts as a bridge between Terraform and your Python code:
- Terraform calls your provider via gRPC
- Pyvider handles the protocol communication
- Your Python code handles the business logic
- Pyvider translates responses back to Terraform
See Architecture for details.
What is the Component Hub?¶
The Component Hub is Pyvider's auto-discovery system. When you use decorators like @register_provider or @register_resource, components automatically register themselves with the hub. Terraform can then discover and use them.
See Component Model.
Do I need to understand the Terraform Plugin Protocol?¶
No! Pyvider abstracts away the protocol details. You just implement: - Provider configuration - Resource CRUD operations - Data source reads - Function calls
Pyvider handles all the gRPC, message serialization, and protocol compliance.
Development Questions¶
How do I start building a provider?¶
Follow these steps:
- Read the Quick Start - Build your first provider in 5 minutes
- Try the Tutorial - Build a real HTTP API provider
- Study Examples - 100+ working examples
- Read the Guides - Creating Providers, Creating Resources
What's the difference between a resource and a data source?¶
Resources manage infrastructure lifecycle (create, update, delete):
@register_resource("server")
class Server(BaseResource):
async def _create_apply(self, ctx):
# Create the server
pass
Data Sources fetch read-only data:
@register_data_source("user")
class User(BaseDataSource):
async def read(self, ctx):
# Fetch user data
pass
See Core Concepts.
How do I handle secrets and credentials?¶
-
Mark as sensitive in schema:
-
Use private state for encrypted storage:
-
Never hardcode secrets in code
-
Never log sensitive data
How do I test my provider?¶
Use pytest with async support:
import pytest
@pytest.mark.asyncio
async def test_resource_create():
resource = MyResource()
ctx = ResourceContext(config=MyConfig(...))
state, _ = await resource._create_apply(ctx)
assert state.id
See Testing Providers.
How do I debug my provider?¶
Enable debug logging:
Use the Python debugger:
See Debugging Guide.
Schema Questions¶
What are the available attribute types?¶
Pyvider provides comprehensive type support:
- Primitives:
a_str(),a_num(),a_bool() - Collections:
a_list(),a_map(),a_set() - Complex:
a_obj(),a_tuple() - Special:
a_dyn()(any type)
See Schema Types.
How do I make an attribute required?¶
How do I add a default value?¶
How do I make an attribute computed?¶
How do I validate attribute values?¶
Use validators:
See Schema Validators.
Can I have nested blocks?¶
Yes! Use block factories:
schema = s_resource({
"name": a_str(required=True),
"config": b_single("config"), # Single nested block
"rule": b_list("rule"), # Multiple blocks
})
See Schema Blocks.
Performance Questions¶
Is Python fast enough for a Terraform provider?¶
Yes, for most use cases. Terraform providers are typically I/O bound (API calls, network), not CPU bound. Python's async/await handles I/O efficiently.
Tips for performance: - Use async/await properly - Implement connection pooling - Cache expensive lookups - Batch API calls
How do I make my provider faster?¶
- Use async properly - Never block the event loop
- Cache data - Cache expensive API calls
- Batch operations - Avoid N+1 queries
- Connection pooling - Reuse HTTP connections
- Profile - Use py-spy to find bottlenecks
Should I use caching?¶
Cache data that: - Changes infrequently (region info, image catalogs) - Is expensive to fetch - Is accessed multiple times
Don't cache: - Resource state (must be fresh) - User credentials - Frequently changing data
Deployment Questions¶
How do I distribute my provider?¶
Options:
- Development - Use
pyvider installfor local testing - Internal - Package with Flavor and distribute binary
- Public - Publish to Terraform Registry (after 1.0)
See Installation Guide.
Does my provider need to be compiled?¶
No! Pyvider providers run as Python scripts. However, you can package them into standalone binaries using Flavor for easier distribution.
Can I publish to the Terraform Registry?¶
Not yet. Public registry support is planned for post-1.0. For now, use: - Local dev provider file - Private distribution - Internal package repository
Troubleshooting¶
Why isn't Terraform finding my provider?¶
Check:
1. Provider is installed (pyvider install)
2. Terraform is initialized (terraform init)
3. Provider name matches in Terraform config
4. Provider is in the correct directory
See Troubleshooting.
Why isn't my resource updating?¶
Ensure you implemented _update_apply():
async def _update_apply(self, ctx):
# Actually update the resource
await self.api.update_resource(ctx.state.id, ctx.config)
return updated_state, None
See Troubleshooting.
Why isn't drift being detected?¶
Implement read() correctly - it must fetch current state, not return cached state:
async def read(self, ctx):
# Fetch CURRENT state from API
current = await self.api.get_resource(ctx.state.id)
return State(**current) # Return current, not ctx.state!
See Troubleshooting.
Why is my provider crashing?¶
Common causes: 1. Unhandled exceptions 2. Blocking I/O in async code 3. Missing await on async calls 4. Type mismatches
Enable debug logging and check for stack traces:
See Troubleshooting.
Advanced Questions¶
Can I use capabilities?¶
Capabilities are experimental. For production, use: - Inheritance (base classes) - Composition (helper classes) - Utility modules
How do I handle provider-specific state?¶
Use instance variables in your provider:
@register_provider("mycloud")
class MyCloudProvider(BaseProvider):
async def configure(self, config):
await super().configure(config)
self.api_client = APIClient(config["api_key"])
self.cache = {}
Resources can access the provider via the hub:
from pyvider.hub import hub
provider = hub.get_component("singleton", "provider")
await provider.api_client.create(...)
Can I have multiple providers in one package?¶
Yes! Register multiple providers:
@register_provider("aws")
class AWSProvider(BaseProvider):
pass
@register_provider("gcp")
class GCPProvider(BaseProvider):
pass
Each will be available as a separate Terraform provider.
How do I handle pagination?¶
Fetch all pages before returning:
async def read(self, ctx):
all_items = []
page_token = None
while True:
response = await provider.api.list_items(
page_token=page_token,
page_size=100
)
all_items.extend(response.items)
if not response.next_page_token:
break
page_token = response.next_page_token
return ItemsData(items=all_items, count=len(all_items))
How do I implement resource timeouts?¶
Use asyncio.wait_for:
import asyncio
async def _create_apply(self, ctx):
try:
# Timeout after 5 minutes
result = await asyncio.wait_for(
self.api.create_resource(ctx.config),
timeout=300
)
return State(**result), None
except asyncio.TimeoutError:
raise ResourceError("Resource creation timed out after 5 minutes")
Getting Help¶
Where can I get help?¶
- Documentation: https://foundry.provide.io/pyvider/
- Examples: pyvider-components
- Discussions: GitHub Discussions
- Issues: GitHub Issues
How do I report a bug?¶
Open an issue with: - Clear description - Steps to reproduce - Environment details (Pyvider version, Python version, OS) - Relevant logs
How can I contribute?¶
We welcome contributions!
- Read Contributing Guidelines
- Find a good first issue
- Submit a pull request
Additional Resources¶
Don't see your question? Ask in GitHub Discussions!