Operators & Dependencies

r8s tracks Kubernetes operator dependencies automatically. No more "forgot to install cert-manager" surprises.

The Problem

You deploy your app. Everything looks fine. Then you realize:

  • ❌ The Ingress doesn't work — nginx-ingress isn't installed
  • ❌ TLS certificates aren't issued — cert-manager is missing
  • ❌ Database pods are stuck — CloudNativePG operator isn't running

These errors show up after deployment, often in production. The dependencies are documented somewhere, but not enforced.

The r8s Way

Every r8s component declares its operator dependencies explicitly. When you render your infrastructure, operators are fetched and included automatically — no manual installation needed.

import { Database, Endpoint } from '@r8s/recipes';

export default (
  <>
    <Database name="app-db" storage="10Gi" />
    <Endpoint host="app.example.com" serviceName="app" />
  </>
>);
import { render } from '@r8s/core';

const result = render(<MyApp />);

// Kubernetes resources
console.log(result.resources);
// [Cluster, Secret, Ingress, Service, ...]
// Required operators (auto-detected)
console.log(result.operators);

How It Works

01

Declare

Components declare operators using declareOperator(). This happens inside the component, close to where the operator is actually used.

02

Collect

The renderer walks the component tree and collects all operator declarations. Duplicates are automatically removed.

03

Include

Operator manifests are fetched from their URLs and included in the rendered YAML. Everything is applied together.

Operators Included Automatically

When you run r8s render, operators are fetched and prepended to your resources:

# r8s render automatically fetches and includes operators
# No manual installation needed

# Operator: cnpg v1.22.5
apiVersion: v1
kind: Namespace
metadata:
  name: cnpg-system
---
# Your resources
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: app-db
spec:
  storage:
    size: 10Gi

Automatic Deduplication

Multiple components can declare the same operator. r8s deduplicates them automatically:

// Component A declares cnpg
function DatabaseA() {
  return [
    declareOperator(cnpgOperator('1.22.5')),
    <Cluster name="db-a" storage="10Gi" />,
  ];
}

// Component B also declares cnpg
function DatabaseB() {
  return [
    declareOperator(cnpgOperator('1.22.5')),
    <Cluster name="db-b" storage="10Gi" />,
  ];
}

// Result: cnpg appears only once in operators list
const result = render(
  <>
    <DatabaseA />
    <DatabaseB />
  </>
);

console.log(result.operators);
// [{ name: 'cnpg', ... }] — deduplicated!

Shared Operators via Context

For a complete platform, provide shared operators via context. Components won't duplicate them:

import { OperatorContext } from '@r8s/core/defaults';
import { Database, Endpoint } from '@r8s/recipes';
import { cnpgOperator, nginxIngressOperator } from '@r8s/recipes';
import { certManagerOperator } from '@r8s/cert-manager';

export default function Platform() {
  return (
    <OperatorContext.Provider value={[
      cnpgOperator('1.22.5'),
      certManagerOperator('1.14.0'),
      nginxIngressOperator('1.15.1'),
    ]}>
      <Database name="app-db" storage="10Gi" />
      <Endpoint host="app.example.com" serviceName="app" />
    </OperatorContext.Provider>
  );
}

Creating Custom Operators

Building your own components? Declare their operator dependencies with manifest URLs:

import { declareOperator } from '@r8s/core';

export const myOperator = declareOperator({
  name: 'my-operator',
  source: {
    type: 'manifest',
    url: 'https://example.com/operator.yaml',
    version: '1.0.0',
  },
});

export function MyComponent(props: { name: string }) {
  return [
    myOperator,
    <deployment
      metadata={{ name: props.name }}
      spec={{ replicas: 1, template: { spec: { containers: [{ name: 'app', image: 'myapp' }] } } }}
    />,
  ];
}

Available Operators

OperatorPackagePurposeSource
CloudNativePG@r8s/recipesPostgreSQL clustersmanifest
nginx-ingress@r8s/recipesHTTP routingmanifest
cert-manager@r8s/cert-managerTLS certificatesmanifest
external-dns@r8s/external-dnsDNS managementmanifest
Vault Secrets@r8s/openbaoSecret managementmanifest
Keycloak@r8s/keycloakIdentity managementmanifest
Redis@r8s/redisRedis clustersmanifest
Prometheus@r8s/prometheusMonitoring stackmanifest

Ready to use operators?

Check out the recipes to see operators in action, or read about deployment strategies with FluxCD.