Next.js + Turborepo + Woodpecker CI: fast builds, PR instances, no vendor lock-in
Remote turbo caching turns ten-minute builds into ten-second cache replays, and a self-hosted Woodpecker pipeline deploys every PR as its own preview instance. The setup behind this very website.
This website is a Next.js app in a Turborepo monorepo, built by a self-hosted Woodpecker CI, deployed to our own Kubernetes clusters — with a live preview instance for every pull request. No GitHub Actions minutes, no Vercel bill, no lock-in. Here's why this stack earns its keep.
Turborepo: never build the same thing twice
Turborepo hashes every task's inputs — source files, dependencies, environment — and caches the outputs. Unchanged input means the build is replayed, not repeated:
web:build: cache hit, replaying logs 62d4aba75ab14869
Tasks: 2 successful, 2 total
Time: 53ms >>> FULL TURBOThat's a full production build of this site in 53 milliseconds, because nothing changed since the last one.
Remote caching: the whole team shares one memory
The local cache is nice; the remote cache is the multiplier. Point turbo at a shared cache backend and every environment — your laptop, a colleague's machine, every CI runner — reads and writes the same artifact store:
turbo build --api="https://cache.internal" --team="codeagency" --token="$TURBO_TOKEN"CI stops rebuilding what a developer already built locally. A pipeline that compiled everything in ten minutes now spends its time only on what actually changed. Self-hosted cache servers (like ducktors/turborepo-remote-cache) make this work without any Vercel account — it's an open protocol over HTTP.
Woodpecker: CI that lives in your cluster
Woodpecker is a lightweight, open-source CI that runs as a couple of pods in the same Kubernetes cluster as the workloads it deploys. Pipelines are a YAML file in the repo:
steps:
install: { image: node:26-slim, commands: [corepack enable, pnpm install --frozen-lockfile] }
quality: { commands: [pnpm lint, pnpm typecheck] }
build: { commands: [pnpm build] }Because it's ours, there are no per-minute charges, no queue behind other people's builds, and no third party holding deploy credentials to our infrastructure. The runners are inside the cluster — deploying is a local operation.
PR preview instances: review running software, not diffs
The pipeline's best trick: every pull request gets labelled, built, and deployed as its own isolated instance with its own URL. Reviewers click through the actual feature on the actual stack — not a screenshot, not a local checkout. Merge it and the preview is torn down; the same tested artifact rolls to production.
Code review catches bad code. Preview instances catch bad software — the layout that breaks on a phone, the form that fails against real latency. Different bug classes, both caught before production.
The same recipe, any project
This exact setup — monorepo, shared cache, in-cluster CI, previews per PR — is what we bring to every custom web application we build and host. It's not exotic; it's just owning your pipeline instead of renting it.
Get the next one in your inbox
New articles, videos and the occasional engineering note — a short mail when there’s something worth reading, nothing else.