on_observe reports whether that object exists and what it looks like; on_create, on_update, and on_delete converge it to the configuration.
Method Signatures
async and run within the provider runtime. Do I/O through an async client or await asyncio.to_thread(...), so a handler yields to the event loop and can be cancelled.
on_observe is mandatory unless the resource is computed. Registering a non-computed class without it raises MissingObserveError when the provider package is imported, so pragma providers publish fails naming the resource type.
Instance Attributes
Inside lifecycle methods, you have access to several instance attributes:on_create
Called when a resource is first created. Your implementation should provision the underlying infrastructure and return the outputs.Outputs class containing values that other resources can reference.
on_observe
Reports the external object this resource owns. Locate it solely from identity (self.project_id, self.name) and self.config, including resolved dependencies, never from self.outputs. Read only the external system, never other resources; a handler that needs another resource declares a Dependency.
None when no object exists for this identity. Otherwise the same Outputs the write path returned for that state.
Errors: Let anything other than “not found” propagate. An exception means the observation failed, not that the object is absent. When the external system can hold more than one match for the key, raise on more than one match.
Stable outputs: Every output field is derived from identity or config, or read from the object once the write path has waited for it to be ready, and on_observe reads it the same way. Values that change without a platform write, such as replica readiness, counters, or indexing status, belong in health(), never in outputs.
on_update
Called to converge an existing object to the current configuration. Receives the previous configuration so you can limit the work to what changed.previous_config: The configuration from the previous successful apply, orNonewhen the object exists but the platform holds no prior configuration. OnNone, skip “unchanged, return early” shortcuts and apply the full desired state.
Outputs class, read from the converged object.
Common Update Patterns
Immutable fields - Fields that cannot change in place, and every fieldon_observe reads to locate the object, are declared ImmutableField or ImmutableDependency. The platform refuses a change to them, so a user changes one by deleting and recreating the resource. The handler never checks them:
on_delete
Called when a resource is being removed. Clean up the underlying infrastructure.Idempotency Requirements
This happens when:- The runtime restarts after executing a method but before confirming completion
- Network issues cause retries
- The user re-applies the same configuration
Idempotent Create
Handle the case where a previous attempt already created the resource by reading it instead:Idempotent Delete
Handle the case where the resource is already gone; that counts as success:Idempotent Update
Compare the live object with the configuration and write only the difference. Withprevious_config=None, never assume nothing changed:
Error Handling
Raise exceptions to signal failures. The runtime will:- Mark the resource as
failed - Record the error message
- Stop processing dependent resources
ValueError- Invalid configuration (user error)RuntimeError- Infrastructure or API failures- Let unexpected exceptions propagate with full tracebacks
Complete Example
Computed Resources
A resource with no external object of its own declarescomputed = True. It needs no on_observe: its outputs derive from its configuration, or from the subresources it owns. Composition resources that only assemble subresources are computed.
Creating Subresources
Providers can create and manage subresources from within lifecycle handlers. This enables composition patterns where a high-level resource provisions multiple lower-level resources.The Pattern
Build the subresource instance, set this resource as its owner, and apply it:apply() returns once the platform accepts the subresource, and the platform provisions it after the handler returns. A resource that needs the subresource’s outputs, such as its connection string, declares a Dependency or a field reference on it; the platform runs that resource only once the subresource is ready, with the values resolved. See Configuration and Outputs.
Methods
set_owner(parent) - Establishes an ownership relationship. When the parent resource is deleted, owned subresources are automatically cleaned up via cascading deletes. Returns self for method chaining.
apply() - Sends the resource to the API for creation or update and returns once the API accepts it. The platform then provisions the resource with the provider that handles its type. Returns self for method chaining.
Complete Example
Here’s a complete example of an application resource that provisions its own database, using theDatabase resource from the complete example above. The application owns no external object of its own, so it is computed, and its outputs derive from its own identity: