cradle

cradle

Where projects are born.

An opinionated TypeScript monorepo template: typesafe APIs, one-command local dev, CI, and deploys. Production-ready from the first commit.

gh repo create my-app --template austinbiggs/cradle
View on GitHub ↗·Read the docs ↗

Day one, in one take

~/my-app
$gh repo create my-app --template austinbiggs/cradle
✓ Created repository my-app
$cd my-app && pnpm install
$pnpm scaffold api && pnpm scaffold web
✓ apps/api · apps/web scaffolded
$tilt up
✓ all healthy: postgres · redis · meilisearch · api · web · docs
my-app was born. 0 errors, 0 warnings.
$

What you get

api

Typesafe API

Fastify + tRPC, end-to-end typed. Supabase JWKS auth, rate limiting, CORS, two-tier cache, health checks, graceful shutdown.

web

React frontends

A Next.js 16 web app with standalone Docker output, a Nextra docs site, and this landing page on TanStack Start + Vite. Keep what fits, delete the rest.

packages

Shared packages, no build step

@cradle/auth · cache · db · telemetry · common, consumed as raw .ts source. Nothing to compile in the inner loop.

env

Fail-fast, typed env

Declarative Varlock .env.schema per app, validated before boot with generated types. Bad config never reaches runtime.

dev

One-command local stack

tilt up brings up Postgres, Redis, Meilisearch, and every app. The whole dependency graph, locally.

deploy

Deploys built in

GitHub Actions → GHCR → Dokploy with Sentry sourcemaps and a /ready health gate. Renovate keeps dependencies fresh.

search

First-class search

Meilisearch, the Rust-built OSS engine, ships as a first-class service: typo-tolerant, sub-50ms full-text search over denormalized indexes, kept in sync straight from Postgres CDC. Tenant tokens enforce visibility server-side, so public search only ever sees published content.

typo-tolerant<50ms p95tenant tokensCDC sync
TypeScript 6Node 24NXpnpmFastifytRPCNext.jsTanStack StartViteSupabaseRedisMeilisearchVarlockTiltSentryPostHogOpenTelemetryoxlintoxfmtVitestDokploy

Typesafe to the edges

cradle-night
import type { CradleApp } from "@cradle/api";
import { createRouter } from "@cradle/api";
// every project starts somewhere
export const app: CradleApp = createRouter({
name: "my-app",
routes: [health, users],
port: 3000,
});
app.listen(); // born ready

Types flow from the router to the client with no codegen. Environment variables are schema-declared and validated before the process starts. Bad config fails the boot, not the user.

One repo, wired end to end

apps
packages
services
deploy
webNext.js
docsNextra
apiFastify + tRPC
@cradle/*
auth
cache
db
common
telemetry
search
PostgresSupabase
Rediscache
TelemetrySentry · PostHog · OTEL
Meilisearchsearch
git push
GitHub Actionsbuild · test · lint
GHCRcontainer image
Dokployhealth-gated deploy
live
apps
webNext.js
docsNextra
apiFastify + tRPC
packages
@cradle/*
auth
cache
db
common
telemetry
search
services
PostgresSupabase
Rediscache
TelemetrySentry · PostHog · OTEL
Meilisearchsearch
deploy
git pushorigin main
GitHub Actionsbuild · test · lint
GHCRcontainer image
Dokployhealth-gated deploy
live
* yours to rename: pnpm rename-scope @yourorg

How it works

Use the template

Use this template ↗

Create your repo from austinbiggs/cradle on GitHub, then clone it.

Scaffold your apps

pnpm scaffold api

api, web, or both. Each lands in apps/ ready to run.

Make it yours

pnpm rename-scope @yourorg

Retarget the whole workspace's package namespace in one command.

Bring it up

tilt up

Postgres, Redis, and every app. The full local stack in one command.