r8s
Stop writing YAML. Start composing infrastructure.
The Problem
You have a microservice. It needs a Deployment, a Service, routing with TLS, and a PostgreSQL database. That's 300+ lines of YAML boilerplate. Copy-paste between services. Hope you didn't miss an indentation.
❌ Raw YAML — Copy-paste hell
❌ Helm — values.yaml sprawl
❌ Kustomize — Can't abstract logic
The Solution
One component. Three resources. All wired together with sensible defaults.
import { App } from '@r8s/recipes';
export default () => (
<App
name="api"
image="myapp/api:v1.2.3"
host="api.example.com"
/>
);$ npx r8s render
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
---
apiVersion: v1
kind: Service
metadata:
name: api
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-endpoint
# ... 3 resources rendered from 1 componentWhy r8s?
DRY by Default
Your 10 microservices all need the same database setup? One component, imported everywhere.
import { App, Database } from '@r8s/recipes';
export default () => (
<>
<Database name="api-db" storage="10Gi" />
<App
name="api"
image="myapp/api:v1.2.3"
host="api.example.com"
/>
</>
);Type Safety Out of the Box
Misspelled containerPort? TypeScript catches it. Wrong apiVersion? Red squiggly. No more kubectl apply → "error: validation failed."
function App({ environment }: { environment: 'staging' | 'production' }) {
const replicas = environment === 'production' ? 3 : 1;
return (
<deployment
metadata={{ name: 'api' }}
spec={{
replicas,
template: {
spec: {
containers: [{
name: 'api',
image: 'myapp/api:v1',
}],
},
},
}}
/>
);
}Real Code, Real Logic
Use conditionals, loops, and variables. Environment-specific configuration without template syntax nightmares.
Testable Infrastructure
Because r8s components are just TypeScript functions, you can test them with standard tools like Vitest.
import { describe, it, expect } from 'vitest';
import { render } from '@r8s/core';
import { App } from '@r8s/recipes';
describe('MyApp', () => {
it('should create a Deployment with 3 replicas', () => {
const result = render(
<App name="api" image="myapp/api:v1" host="api.example.com" replicas={3} />
);
const deployment = result.resources.find(r => r.kind === 'Deployment');
expect(deployment.spec.replicas).toBe(3);
});
});Quick Start
Create a new project
npx r8s init my-project
cd my-project
npm installEdit your components
import { App } from '@r8s/recipes';
export default () => (
<App
name="myapp"
image="myapp/web:v1.2.3"
host="myapp.example.com"
replicas={3}
/>
);Render to YAML
npx r8s render --out k8s/manifest.yamlRecipes
Pre-built components for common infrastructure patterns.Browse all recipes →
Deploy with AI agents
r8s is designed for LLM-driven workflows. Point your agent at r8s.berget.ai/llms.txt — it contains the quick-start, CLI reference, and the component model. The agent writes TSX, renders with the r8s CLI, and hands plain YAML to your pipeline.
Read https://r8s.berget.ai/llms.txt, then:
Create an r8s project for my API:
- name: api, image: ghcr.io/myorg/api:v1.2.3
- host: api.example.com, 3 replicas, port 3000
- PostgreSQL database (20Gi)
Render to k8s/manifest.yaml.Comparison
| Raw YAML | Helm | Kustomize | r8s | |
|---|---|---|---|---|
| Composition | ❌ Copy-paste | ⚠️ Templates | ❌ Patches only | ✅ Components |
| Type Safety | ❌ | ❌ | ❌ | ✅ Full TS |
| DRY | ❌ | ⚠️ Values files | ⚠️ Bases | ✅ Import & reuse |
| Learning Curve | Low | Medium | Low | Low |
| GitOps Friendly | ✅ | ✅ | ✅ | ✅ Yes |