Skip to content

Web Application Compositions

Higher-level compositions that wire together CNPG PostgreSQL, Valkey cache, Inngest workflow engine, and your application deployment. All connection strings are automatically injected as environment variables.

Import

typescript
import { webAppWithProcessing } from 'typekro/webapp';

webAppWithProcessing

Deploys a complete application stack with automatic wiring:

ComponentResourceWired env var
PostgreSQLCNPG Cluster + PgBouncer PoolerDATABASE_URL
CacheValkey clusterVALKEY_URL, REDIS_URL
Workflow engineInngest (external DB mode)INNGEST_BASE_URL; credentials are injected from a generated Secret via envFrom
ApplicationDeployment + Service

Quick Example

typescript
import { webAppWithProcessing } from 'typekro/webapp';

// 'kro' = continuous reconciliation, 'direct' = immediate apply
const factory = webAppWithProcessing.factory('kro', {
  namespace: 'production',
  waitForReady: true,
});

const instance = await factory.deploy({
  name: 'my-app',
  namespace: 'production',
  app: {
    image: 'my-app:latest',
    port: 3000,
    replicas: 2,
    env: {
      NODE_ENV: 'production',
    },
  },
  database: {
    instances: 3,
    storageSize: '50Gi',
    storageClass: 'gp3',
    database: 'myapp',
  },
  cache: {
    shards: 3,
    replicas: 1,
  },
  processing: {
    eventKey: 'your-hex-event-key',
    signingKey: 'your-hex-signing-key',
    sdkUrl: ['http://my-app:3000/api/inngest'],
  },
});

What gets deployed

Given name: 'my-app', the composition creates:

ResourceNameType
PostgreSQL clustermy-app-dbCNPG Cluster (3 instances)
Connection poolermy-app-db-poolerCNPG Pooler (PgBouncer, transaction mode)
Cachemy-app-cacheValkey cluster
Workflow enginemy-app-inngestInngest (HelmRelease, external DB)
Applicationmy-appDeployment + Service

Environment variables injected into the app

DATABASE_URL=postgresql://app@my-app-db-pooler:5432/myapp
VALKEY_URL=redis://my-app-cache:6379
REDIS_URL=redis://my-app-cache:6379
INNGEST_BASE_URL=http://my-app-inngest:8288
INNGEST_EVENT_KEY=<from generated Secret>
INNGEST_SIGNING_KEY=<from generated Secret>

The composition creates an Inngest credentials Secret and prepends it to app.envFrom for direct deployments. In KRO mode, the generated Inngest credentials Secret is still mounted, but schema-provided app.envFrom entries are not merged into the generated Deployment because KRO cannot safely concatenate typed list fields. User-provided app.env values are still merged on top of generated direct environment variables, so they can override direct values such as DATABASE_URL or INNGEST_BASE_URL.

In KRO mode, processing.eventKey and processing.signingKey are still plain custom-resource spec fields before TypeKro copies them into the generated Secret. Treat webapp custom resources as sensitive and restrict RBAC read access to those CRs.

Status

typescript
instance.status.ready       // all components healthy
instance.status.databaseUrl // postgresql://app@...-db-pooler:5432/...
instance.status.databaseHost // ...-db-pooler
instance.status.databasePort // 5432
instance.status.cacheUrl    // redis://...-cache:6379
instance.status.cacheHost   // ...-cache
instance.status.cachePort   // 6379
instance.status.inngestUrl  // http://...-inngest:8288
instance.status.appUrl      // http://...:3000

instance.status.components.app       // app deployment ready
instance.status.components.database  // CNPG cluster healthy
instance.status.components.cache     // Valkey ready
instance.status.components.inngest   // Inngest ready

Configuration

FieldRequiredDescription
nameYesApp name (prefix for all resources)
namespaceNoTarget namespace (default: 'default')
app.imageYesContainer image
app.portNoContainer port (default: 3000)
app.replicasNoReplica count (default: 1)
app.envNoExtra env vars (merged with auto-wired ones)
app.envFromNoAdditional Secret/ConfigMap envFrom sources for direct deployments. TypeKro prepends the generated Inngest credentials Secret, so later entries can override only by defining the same env keys in a later source according to Kubernetes envFrom behavior. In KRO mode, only the generated Inngest credentials Secret is mounted
database.storageSizeYesPG storage (e.g., '50Gi')
database.instancesNoPG replicas (default: 1)
database.storageClassNoStorage class
database.databaseNoDatabase name (default: app)
database.ownerNoDB owner (default: 'app')
cache.shardsNoValkey shards (default: 3)
cache.replicasNoReplicas per shard (default: 0)
cache.volumePermissionsNoEnable the Valkey volume permissions init container
cache.storageSizeNoStorage size per Valkey shard (default: '1Gi')
processing.eventKeyYesInngest event key (hex string); sensitive in KRO custom-resource specs
processing.signingKeyYesInngest signing key (hex string); sensitive in KRO custom-resource specs
processing.sdkUrlNoApp SDK URLs for function sync
processing.replicasNoInngest server replicas (default: 1)
processing.resourcesNoCPU/memory requests and limits for the Inngest server
cnpgOperatorNoCloudNativePG operator singleton settings; accepts the underlying CNPG bootstrap fields such as name, namespace, version, resources, customValues, and shared. name/namespace customize the install target; the singleton identity is fixed by the composition.
valkeyOperatorNoValkey operator singleton settings; accepts the underlying Valkey bootstrap fields such as name, namespace, version, resources, customValues, and shared. name/namespace customize the install target; the singleton identity is fixed by the composition.

Prerequisites

Install the TypeKro runtime first so Flux and KRO are available. The webapp composition bootstraps CloudNativePG and Valkey operators itself as shared singleton dependencies.

  • TypeKro runtime — Flux CD plus KRO controller
  • CloudNativePG operator — bootstrapped by this composition
  • Valkey operator — bootstrapped by this composition
typescript
import { typeKroRuntimeBootstrap } from 'typekro';

// Install runtime first
await typeKroRuntimeBootstrap().factory('direct', { ... }).deploy({ ... });

// Then deploy the full stack; CNPG and Valkey operator singletons are included
await webAppWithProcessing.factory('kro', { ... }).deploy({ ... });

Next Steps

Released under the Apache 2.0 License.