Factory Functions
Factory functions are the building blocks of TypeKro. They provide type-safe, pre-configured ways to create common Kubernetes resources with sensible defaults and full TypeScript support.
Overview
Instead of writing verbose Kubernetes YAML, factory functions let you create resources with clean, typed APIs:
// Instead of this YAML...
/*
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:latest
ports:
- containerPort: 80
*/
// Write this TypeScript
const deployment = simpleDeployment({
name: 'my-app',
image: 'nginx:latest',
replicas: 3,
ports: [{ containerPort: 80 }]
});
Core Factory Functions
Workloads
simpleDeployment
Creates a Kubernetes Deployment with sensible defaults.
import { simpleDeployment } from 'typekro';
const deployment = simpleDeployment({
name: 'web-app',
image: 'nginx:latest',
replicas: 3,
ports: [{ containerPort: 80 }],
env: {
NODE_ENV: 'production',
API_URL: 'https://api.example.com'
},
resources: {
cpu: '500m',
memory: '1Gi'
}
});
Key Features:
- Automatic label generation (
app: name
) - Health check configuration
- Resource limits and requests
- Environment variable support
- Volume mounting
simpleStatefulSet
Creates a StatefulSet for stateful applications.
const database = simpleStatefulSet({
name: 'postgres',
image: 'postgres:15',
replicas: 1,
ports: [{ containerPort: 5432 }],
env: {
POSTGRES_DB: 'myapp',
POSTGRES_USER: 'user',
POSTGRES_PASSWORD: 'password'
},
volumeClaimTemplates: [{
name: 'data',
size: '10Gi',
storageClass: 'fast-ssd'
}],
volumeMounts: [{
name: 'data',
mountPath: '/var/lib/postgresql/data'
}]
});
simpleJob
Creates a Kubernetes Job for batch processing.
const migrationJob = simpleJob({
name: 'db-migration',
image: 'myapp/migrations:latest',
env: {
DATABASE_URL: database.status.podIP
},
restartPolicy: 'OnFailure',
backoffLimit: 3
});
Networking
simpleService
Creates a Kubernetes Service to expose applications.
const service = simpleService({
name: 'web-service',
selector: { app: 'web-app' },
ports: [
{ port: 80, targetPort: 8080 },
{ port: 443, targetPort: 8443, name: 'https' }
],
type: 'LoadBalancer'
});
Service Types:
ClusterIP
(default) - Internal cluster accessNodePort
- Access via node portsLoadBalancer
- External load balancerExternalName
- DNS CNAME record
simpleIngress
Creates an Ingress resource for HTTP routing.
const ingress = simpleIngress({
name: 'web-ingress',
rules: [{
host: 'myapp.example.com',
http: {
paths: [{
path: '/',
pathType: 'Prefix',
backend: {
service: {
name: service.metadata.name,
port: { number: 80 }
}
}
}]
}
}],
tls: [{
secretName: 'web-tls',
hosts: ['myapp.example.com']
}]
});
Configuration
simpleConfigMap
Creates a ConfigMap for application configuration.
const config = simpleConfigMap({
name: 'app-config',
data: {
'app.properties': `
server.port=8080
database.url=jdbc:postgresql://postgres:5432/myapp
logging.level=INFO
`,
'nginx.conf': `
server {
listen 80;
location / {
proxy_pass http://backend:8080;
}
}
`
}
});
simpleSecret
Creates a Secret for sensitive data.
const secret = simpleSecret({
name: 'app-secrets',
data: {
'database-password': 'c3VwZXJzZWNyZXQ=', // base64 encoded
'api-key': 'YWJjZGVmZ2hpams='
},
type: 'Opaque'
});
// Or use stringData for automatic base64 encoding
const secretFromStrings = simpleSecret({
name: 'app-secrets',
stringData: {
'database-password': 'supersecret',
'api-key': 'abcdefghijk'
}
});
Storage
simplePvc
Creates a PersistentVolumeClaim for storage.
const storage = simplePvc({
name: 'app-storage',
size: '10Gi',
storageClass: 'fast-ssd',
accessModes: ['ReadWriteOnce']
});
Advanced Factory Usage
Cross-Resource References
Factory functions can reference other resources:
const database = simpleDeployment({
name: 'postgres',
image: 'postgres:15'
});
const app = simpleDeployment({
name: 'web-app',
image: 'myapp:latest',
env: {
// Reference the database's pod IP
DATABASE_HOST: database.status.podIP,
DATABASE_PORT: '5432'
}
});
const service = simpleService({
name: 'web-service',
// Reference the app's labels
selector: { app: app.metadata.labels.app },
ports: [{ port: 80, targetPort: 3000 }]
});
Conditional Configuration
Use TypeScript's conditional logic:
const deployment = simpleDeployment({
name: schema.spec.name,
image: schema.spec.image,
replicas: schema.spec.environment === 'production' ? 5 : 2,
// Production gets more resources
resources: schema.spec.environment === 'production'
? { cpu: '1000m', memory: '2Gi' }
: { cpu: '100m', memory: '256Mi' },
// Enable health checks in production
...(schema.spec.environment === 'production' && {
livenessProbe: {
httpGet: { path: '/health', port: 3000 },
initialDelaySeconds: 30
},
readinessProbe: {
httpGet: { path: '/ready', port: 3000 },
initialDelaySeconds: 5
}
})
});
Custom Labels and Annotations
const deployment = simpleDeployment({
name: 'my-app',
image: 'nginx:latest',
// Custom labels (merged with defaults)
labels: {
version: 'v1.2.3',
team: 'platform',
environment: 'production'
},
// Custom annotations
annotations: {
'deployment.kubernetes.io/revision': '1',
'prometheus.io/scrape': 'true',
'prometheus.io/port': '9090'
}
});
Factory Function Patterns
Environment-Specific Factories
Create environment-specific factory functions:
function productionDeployment(config: DeploymentConfig) {
return simpleDeployment({
...config,
replicas: Math.max(config.replicas, 3), // Minimum 3 replicas
resources: {
cpu: '500m',
memory: '1Gi',
...config.resources
},
livenessProbe: {
httpGet: { path: '/health', port: config.port || 3000 },
initialDelaySeconds: 30,
periodSeconds: 10
},
readinessProbe: {
httpGet: { path: '/ready', port: config.port || 3000 },
initialDelaySeconds: 5,
periodSeconds: 5
}
});
}
Composition Patterns
Combine multiple factory functions:
function webAppStack(config: WebAppConfig) {
const configMap = simpleConfigMap({
name: Cel.expr(config.name, '-config'),
data: config.configData
});
const secret = simpleSecret({
name: Cel.expr(config.name, '-secrets'),
stringData: config.secrets
});
const deployment = simpleDeployment({
name: config.name,
image: config.image,
replicas: config.replicas,
env: {
...config.env,
CONFIG_PATH: '/etc/config'
},
volumeMounts: [
{ name: 'config', mountPath: '/etc/config' },
{ name: 'secrets', mountPath: '/etc/secrets' }
],
volumes: [
{ name: 'config', configMap: { name: configMap.metadata.name } },
{ name: 'secrets', secret: { secretName: secret.metadata.name } }
]
});
const service = simpleService({
name: Cel.expr(config.name, '-service'),
selector: { app: config.name },
ports: config.ports
});
return { configMap, secret, deployment, service };
}
Type Safety Features
Compile-Time Validation
Factory functions provide full TypeScript validation:
// ✅ This works
const deployment = simpleDeployment({
name: 'my-app',
image: 'nginx:latest',
replicas: 3
});
// ❌ TypeScript errors
const badDeployment = simpleDeployment({
name: 123, // Error: number not assignable to string
image: 'nginx:latest',
replicas: '3', // Error: string not assignable to number
invalidField: true // Error: object literal may only specify known properties
});
IDE Support
Get full autocomplete and documentation:
const deployment = simpleDeployment({
name: 'my-app',
image: 'nginx:latest',
// IDE shows all available options with documentation
resources: {
// Autocomplete for cpu, memory, etc.
},
// Hover for parameter documentation
});
Custom Factory Functions
Create your own factory functions for common patterns:
import { createResource } from 'typekro';
export function customWebApp(config: CustomWebAppConfig) {
return createResource({
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: config.name,
labels: {
app: config.name,
tier: 'web',
version: config.version
}
},
spec: {
replicas: config.replicas,
selector: {
matchLabels: { app: config.name }
},
template: {
metadata: {
labels: { app: config.name }
},
spec: {
containers: [{
name: config.name,
image: config.image,
ports: config.ports,
env: Object.entries(config.env || {}).map(([name, value]) => ({
name,
value: String(value)
})),
// Custom logic here
securityContext: {
runAsNonRoot: true,
runAsUser: 1000,
allowPrivilegeEscalation: false
}
}]
}
}
}
});
}
Best Practices
1. Use Descriptive Names
// ✅ Good
const userApiDeployment = simpleDeployment({ name: 'user-api' });
const userApiService = simpleService({ name: 'user-api-service' });
// ❌ Avoid
const d1 = simpleDeployment({ name: 'app' });
const s1 = simpleService({ name: 'svc' });
2. Group Related Resources
const userService = {
deployment: simpleDeployment({ /* ... */ }),
service: simpleService({ /* ... */ }),
configMap: simpleConfigMap({ /* ... */ })
};
3. Use Environment Variables for Configuration
const deployment = simpleDeployment({
name: 'api',
image: process.env.API_IMAGE || 'api:latest',
replicas: parseInt(process.env.API_REPLICAS || '3'),
env: {
NODE_ENV: process.env.NODE_ENV || 'production',
LOG_LEVEL: process.env.LOG_LEVEL || 'info'
}
});
4. Validate Configuration
import { type } from 'arktype';
const DeploymentConfig = type({
name: 'string>2', // At least 3 characters
image: 'string',
replicas: 'number>0', // At least 1
environment: '"dev" | "staging" | "prod"'
});
function createDeployment(config: unknown) {
const validConfig = DeploymentConfig(config);
if (validConfig instanceof type.errors) {
throw new Error(Cel.template('Invalid config: %s', validConfig.summary));
}
return simpleDeployment(validConfig);
}
Next Steps
- Cross-Resource References - Connect resources dynamically
- CEL Expressions - Add runtime logic
- Custom Factory Functions - Build your own factories
- API Reference - Complete factory function reference