CustomResource
A CustomResource allows you to define infrastructure resources that are not natively supported by Kyku. It runs a user-provided handler function during apply and destroy phases, with access to provider clients and secret management. This is the escape hatch for extending Kyku to any cloud API.
Config
Section titled “Config”| Property | Type | Required | Description |
|---|---|---|---|
name |
string |
yes | Unique resource name |
id |
string |
no | Explicit ID (auto-generated UUID if omitted) |
provider |
string |
no | Provider label for multi-provider configs |
tags |
Record<string, string> |
no | Arbitrary key-value metadata |
handlerId |
string |
yes | Registered handler identifier |
properties |
Record<string, unknown> |
yes | Arbitrary properties passed to the handler |
Handler Interface
Section titled “Handler Interface”interface CustomResourceHandler { apply: (context: CustomResourceContext) => Promise<CustomResourceResult> destroy?: (context: CustomResourceContext) => Promise<void>}
interface CustomResourceContext { readonly id: string readonly name: string readonly properties: Record<string, unknown> readonly previousProperties?: Record<string, unknown> readonly previousState?: Record<string, unknown> readonly previousProviderId?: string getClient: (name: string) => ProviderClient setSecret: <T>(value: T) => T & { __secret: true } getOutput: (resourceId: string, key: string) => Promise<unknown> readonly log: (message: string) => void}
interface CustomResourceResult { providerId: string outputs?: Record<string, unknown> status?: string}
interface ProviderClient { readonly client: unknown readonly region: string}Example
Section titled “Example”import { CustomResource, CustomResourceRegistry } from '@kykucloud/types'
// Register a handlerCustomResourceRegistry.register('my-custom-handler', { async apply(context) { const aws = context.getClient('aws') // AWS SDK client context.log('Creating custom resource…') return { providerId: 'custom-123', outputs: { endpoint: '…' } } }, async destroy(context) { context.log('Cleaning up…') },})
// Use it in configconst myCustom = new CustomResource({ name: 'my-custom', handlerId: 'my-custom-handler', properties: { configA: 'value1', configB: 42, },})Provider Support
Section titled “Provider Support”| Provider | Supported | Backend |
|---|---|---|
| AWS | ✅ | Wired — can access any AWS SDK v3 service |
| GCP | ✅ | Wired — can access any GCP API client |
| Hetzner | ✅ | Wired — can access Hetzner API client |
| DigitalOcean | ✅ | Wired — can access DO API client |
- Handler registration: Handlers must be registered with
CustomResourceRegistry.register(handlerId, handler)before the plan/apply phase. - Provider clients:
context.getClient('aws')returns the AWS SDK v3 client,context.getClient('gcp')returns the GCP auth client. The available clients depend on the provider used. - Secrets: Use
context.setSecret(value)(or the exportedsetSecret()) to wrap a value. The crypto walk encrypts the inner string and unwraps the marker so state storesENC:ciphertext. - Outputs: Return
outputsin the result to expose values that can be referenced by other resources. - Destroy: If
destroyis not provided, the resource will be removed from state without any cleanup. - State tracking: The result’s
providerIdis used for tracking and drift detection on subsequent applies.