Skip to content

Cloudticon

TypeScript-first Kubernetes ecosystem.
Terminal window
curl -fsSL https://cloudticon.com/install.sh | sudo sh

Readable, type-safe resource definitions with IDE autocomplete — no boilerplate, no templating hacks.

What you write
What Kubernetes gets
import { deployment, service, ingress } from "github.com/cloudticon/k8s@master";
const app = "api";
const labels = {
"app.kubernetes.io/name": app,
"app.kubernetes.io/part-of": "acme-platform",
"app.kubernetes.io/managed-by": "ct",
};
deployment({
name: app,
labels,
image: "ghcr.io/acme/api:2.1.0",
replicas: 3,
resources: {
requests: { cpu: "100m", memory: "128Mi" },
limits: { cpu: "500m", memory: "512Mi" },
}
});
service({
name: app,
labels,
selector: labels,
ports: [
{ name: "http", port: 80, targetPort: 8080 },
{ name: "metrics", port: 9090, targetPort: 9090 },
]
});
ingress({
name: app,
labels,
rules: [
{
host: "api.acme.com",
http: {
paths: [
{
path: "/",
pathType: "Prefix",
backend: { service: app, port: 80 },
},
],
},
},
]
});
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
template:
metadata:
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
spec:
containers:
- name: api
image: ghcr.io/acme/api:2.1.0
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: api
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
spec:
selector:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
ports:
- name: http
port: 80
targetPort: 8080
- name: metrics
port: 9090
targetPort: 9090
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
labels:
app.kubernetes.io/name: api
app.kubernetes.io/part-of: acme-platform
app.kubernetes.io/managed-by: ct
spec:
rules:
- host: api.acme.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80

50 lines vs 80 lines — labels repeated 5×, indentation 8 levels deep, and that’s just one microservice. Now imagine scaling that.


Add a dev.ct file next to your resources:

// dev.ct
config({ namespace: "myapp-dev" });
dev("api", {
command: ["npm", "run", "dev"],
sync: [{ from: "./", to: "/app" }],
ports: [[8080, 3000]],
});
Terminal window
ct dev

Port forwarding, file sync, log streaming — all start in parallel. Edit a file locally and it lands in the container instantly. No Docker rebuilds, no separate YAML config. Full CT Dev docs →


You don’t have to use built-in primitives only — create a custom resource factory, push it to GitHub, and every team can import it instantly with a single URL.

1. Define the factory — a plain TypeScript function that calls lower-level primitives:

github.com/acme/k8s-platform/web-stack.ct
import { deployment, service, ingress } from "github.com/cloudticon/k8s@master";
interface WebStackOptions {
name: string;
image: string;
replicas?: number;
host?: string;
}
export function webApp(opts: WebStackOptions) {
const labels = {
"app.kubernetes.io/name": opts.name,
"app.kubernetes.io/managed-by": "ct",
};
deployment({
name: opts.name,
labels,
image: opts.image,
replicas: opts.replicas ?? 1,
resources: {
requests: { cpu: "100m", memory: "128Mi" },
limits: { cpu: "500m", memory: "512Mi" },
},
});
service({
name: opts.name,
labels,
selector: labels,
ports: [{ name: "http", port: 80, targetPort: 8080 }],
});
if (opts.host) {
ingress({
name: opts.name,
labels,
rules: [{ host: opts.host, http: { paths: [{ path: "/", pathType: "Prefix", backend: { service: opts.name, port: 80 } }] } }],
});
}
}

2. Push to GitHub — that’s it. No registry, no publish step.

3. Import anywhere — any .ct file in any repo can pull your factory by URL:

import { webApp } from "github.com/your/repo@master";
webApp({
name: "api",
image: "ghcr.io/acme/api:2.1.0",
replicas: 3,
host: "api.acme.com"
});

CT fetches and caches the module at ct template time — no npm install, no pre-build. Version-pin with a tag (@v1), a branch (@main), or a commit SHA for full reproducibility.


Want less boilerplate for common single-container workloads? Use k8s-factories and start from webApp() plus optional expose() routing.

import { webApp, env, vol } from "github.com/cloudticon/k8s-factories@master";
webApp({
name: "api",
image: "ghcr.io/acme/api:2.1.0",
port: 8080,
env: {
NODE_ENV: "production",
DB_PASSWORD: env.secret("db-credentials", "password"),
},
volumes: {
"/data": vol.pvc({ size: "10Gi" }),
"/cache": vol.emptyDir(),
},
probes: { path: "/health" },
hpa: { min: 2, max: 8, cpu: 75 },
expose: {
type: "istio",
host: "api.acme.com",
},
});

This single call creates Deployment + Service, and can also add HPA, PVC-backed volumes, and inline exposure. For more patterns, see Examples.


.ct files are TypeScript — so you get if, for, map, spread, destructuring, and every other language feature out of the box. No custom DSL, no {{- if }} hacks.

values.json

{
"domain": "acme.com",
"apps": [
{ "name": "api", "image": "ghcr.io/acme/api:2.1.0", "replicas": 3, "public": true },
{ "name": "auth", "image": "ghcr.io/acme/auth:1.0.0", "replicas": 1, "public": false },
{ "name": "billing", "image": "ghcr.io/acme/billing:3.2.1", "replicas": 5, "public": true }
]
}

app.ct

import { deployment, service, ingress } from "github.com/cloudticon/k8s@master";
function labels(app: string) {
return { "app.kubernetes.io/name": app, "app.kubernetes.io/managed-by": "ct" };
}
for (const app of Values.apps) {
deployment({
name: app.name,
labels: labels(app.name),
image: app.image,
replicas: app.replicas,
});
service({
name: app.name,
labels: labels(app.name),
selector: labels(app.name),
ports: [{ name: "http", port: 80, targetPort: 8080 }],
});
if (app.public) {
ingress({
name: app.name,
labels: labels(app.name),
rules: [
{
host: `${app.name}.${Values.domain}`,
http: {
paths: [
{
path: "/",
pathType: "Prefix",
backend: { service: app.name, port: 80 }
}
]
}
}
]
});
}
}

Values come from values.json (or values.yaml) and are fully typed via ct types .. Loop over a list, conditionally create an Ingress, extract a helper function — all in plain TypeScript. No copy-paste drift, no forgotten fields, and the compiler catches every typo.


.ct files are TypeScript — so your editor already knows how to help. Install the CT VS Code extension and run ct types . to unlock:

  • Autocomplete for every field — type deployment({ and see name, image, replicas, resources, labels suggested instantly. No guessing field names, no checking docs mid-flow.
  • Typed ValuesValues.replicas, Values.image come straight from your values.json or values.yaml. Rename a key and the editor flags every broken reference.
  • URL import resolution — types from github.com/cloudticon/k8s@master are fetched, cached, and visible to TypeScript. Jump-to-definition works across packages.
  • Errors before you run — misspell a field, pass a number where a string is expected, forget a required property — red squiggles appear immediately, not after ct template fails.
deployment({
name: "api",
image: "ghcr.io/acme/api:2.1.0",
replicas: "3",
// ~~~ Type 'string' is not assignable to type 'number'
});

The extension watches .ct and values files — types refresh automatically on save. See CT VS Code for setup details.


Terminal window
curl -fsSL https://cloudticon.com/install.sh | sudo sh
ct init my-app
cd my-app
ct template my-app-dev . --namespace default
  1. Install CT.
  2. Initialize a project.
  3. Render resources with a release name.
  4. Iterate in VS Code with IntelliSense and ct types.
  • CT CLI — full command and flag reference, workflows, troubleshooting.
  • ct delete — remove a release from cluster using inventory (no source path required).
  • CT vs Helm — why TypeScript beats Go templates.
  • CT Dev — development mode for Kubernetes — port forwarding, file sync, logs.
  • CT VS Code — extension setup, type generation, diagnostics.
  • K8s Resource Factories — reusable resource() based APIs.
  • K8s High-level FactorieswebApp() and expose() patterns from k8s-factories.
  • CT Operator — runtime and deployment model.