podspawnpodspawn

Real-World Examples

Podfiles from the podspawn project itself -- Go, Node.js, and YAML repos.

Podspawn uses its own tool for development. These are the actual Podfiles committed to each repository in the project. They cover three common setups: a Go backend, a Next.js docs site, and a simple YAML-only repo.

The Podfiles

The main podspawn repo is a Go CLI with golangci-lint, integration tests that need Docker, and a pre-commit hook.

extends: ubuntu-dev

packages:
  - go@1.25

resources:
  cpus: 2.0
  memory: 4g

on_create: |
  go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
  go install github.com/go-delve/delve/cmd/dlv@latest
  go mod download
  make hooks

on_start: |
  echo "podspawn dev: Go $(go version | awk '{print $3}')"
  echo "run 'make test' to verify, 'make lint' to check style"

What this does:

  • extends: ubuntu-dev pulls in git, curl, ripgrep, fzf, neovim, jq, htop, make
  • go@1.25 installs from the official tarball (handled by podspawn's package resolver)
  • on_create downloads Go tools and project dependencies once, then installs the pre-commit hook
  • on_start prints the version on every attach so you know what you're working with
  • No ports exposed -- podspawn is a CLI tool, not a server

golangci-lint and delve are installed via go install in on_create rather than as packages. This is because they're Go tools that need the Go toolchain to install, and podspawn's package resolver doesn't handle them natively.

The docs site uses Fumadocs (Next.js) with bun as the package manager.

extends: ubuntu-dev

packages:
  - nodejs@22

ports:
  expose: [3000]
  strategy: auto

resources:
  cpus: 1.0
  memory: 2g

on_create: |
  npm install -g bun
  bun install

on_start: |
  echo "podspawn-docs: Node $(node --version), bun $(bun --version)"
  echo "run 'bun run dev' to start on port 3000"

What this does:

  • nodejs@22 installs Node via the NodeSource PPA
  • Port 3000 exposed with auto strategy -- if another project uses 3000, podspawn picks the next available
  • on_create installs bun globally, then runs bun install for project deps
  • Lower resources (1 CPU, 2GB) -- docs sites don't need much

bun is installed via npm in on_create rather than as a package. This keeps the Podfile simple and avoids needing a custom package entry for bun.

The podfiles registry is just YAML files and a CI workflow. It needs yq for local validation but almost nothing else.

extends: minimal

on_create: |
  curl -sSfL https://github.com/mikefarah/yq/releases/download/v4.44.1/yq_linux_amd64 \
    -o /usr/local/bin/yq
  chmod +x /usr/local/bin/yq

on_start: |
  echo "podfiles registry: $(ls templates/*.yaml bases/*.yaml | wc -l) files"

What this does:

  • extends: minimal -- only git, curl, ca-certificates. No dev tools needed for editing YAML.
  • on_create fetches a specific version of yq. Pinned version avoids surprises.
  • No packages, no ports, no services, no resources override. The simplest possible Podfile.

Patterns to take away

Use extends to avoid repeating yourself. All three repos extend a base instead of listing git, curl, etc. individually.

Put slow things in on_create. go mod download, bun install, and binary downloads only run once. Fast things like version prints go in on_start.

Don't over-specify. The podfiles repo doesn't declare resources, ports, or shell. Defaults are fine for simple projects.

Pin tool versions. yq is pinned to v4.44.1, Go to 1.25. Pinning prevents "works on my machine" drift between contributors.

Match your CI. These Podfiles mirror what the CI workflows install. If CI uses golangci-lint, so does the Podfile. A contributor's podspawn dev environment matches what CI will test against.

How is this guide?

On this page