DEV Community

Emin Salih Açıkgöz
Emin Salih Açıkgöz

Posted on • Originally published at github.com

Atomic Scaffolding: How scbake Prevents Configuration Mishaps

Project scaffolders help speed up development. Until they fail halfway. Now you're left with a messy directory, half-executed commands, missing files, and no clear way to recover.

I built scbake to solve this problem differently. Every step is transactional. If anything fails, your disk returns to its original state. No cleanup. No mystery files. No manual intervention.

The Problem: Partial Failures

Here's what may happen with traditional scaffolders like cookiecutter:

$ cookiecutter my-template
[1/5] Creating directory... ✓
[2/5] Creating files... ✓
[3/5] Running go mod init... ✓
[4/5] Setting up git... ✗ NETWORK TIMEOUT
Enter fullscreen mode Exit fullscreen mode

This scenario isn't hypothetical. It happens regularly:

  • Network timeouts during file download
  • A missing binary
  • A typo in a template variable
  • Permission denied on directory creation

Each failure leaves your filesystem in a partial state. You either manually clean up the broken directory, or you start working in a half-configured project and discover issues later.

At scale, when you're scaffolding microservices, onboarding teams, or running a SaaS generator, these partial failures compound into wasted time and inconsistent setups.

The Solution: LIFO Transaction Manager

scbake applies database transaction semantics to filesystem operations. Think of it like this: every task is tracked, and if anything goes wrong, scbake rolls back in reverse order (as in LIFO: Last In, First Out).

[1] Create directory
  ↓
[2] Create files
  ↓
[3] Run go mod init
  ↓
[4] Set up git
  ↓
[5] Create initial commit
  ↓
Network error during [5]?

Rollback (reverse order):
  ✓ Delete initial commit
  ✓ Restore git state
  ✓ Restore go mod state
  ✓ Delete files
  ✓ Delete directory
Enter fullscreen mode Exit fullscreen mode

It's the same isolation guarantee you'd get from database transactions. But instead of tables and rows, scbake is managing project files and shell commands.

How scbake Works

scbake organizes tasks into priority bands. Each band must complete before the next begins:

PrioDirCreate (50-99)           → Create project directory
  ↓
PrioLangSetup (100-999)         → Initialize language (go mod, npm, maven)
  ↓
PrioConfigUniversal (1000-1099) → Add EditorConfig, .gitignore
  ↓
PrioCI (1100-1199)              → Set up GitHub Actions
  ↓
PrioLinter (1200-1399)          → Add linters (golangci-lint, ESLint)
  ↓
PrioBuildSystem (1400-1499)     → Add Makefile
  ↓
PrioDevEnv (1500-1999)          → Add dev container
  ↓
PrioVersionControl (2000-2100)  → Initialize git, create first commit
Enter fullscreen mode Exit fullscreen mode

Order matters. You can't lint code that doesn't exist yet. You can't commit if git isn't initialized. Priority bands enforce these constraints.

Animated demo of scbake scaffolding a complete Go + Svelte project with CI/CD, showing command execution, progress steps, final directory structure, and working build tools

A Real Example: Baking a Go Backend

Let's say you want to scaffold a modern full-stack project:

scbake new my-startup --lang go --with makefile ci_github go_linter
Enter fullscreen mode Exit fullscreen mode

This single command executes:

  1. Create my-startup/ directory
  2. Initialize Go module (go mod init, go mod tidy)
  3. Add editor config (.editorconfig, .gitignore)
  4. Set up GitHub Actions (workflow file for testing and linting)
  5. Add golangci-lint (linter configuration)
  6. Create Makefile (build, lint, test targets)
  7. Initialize git (repo init, stage all files, first commit)

Everything's ready. Your main.go compiles. The linter runs. The CI workflow is valid. Git is initialized.

scbake doesn't just stop, it recovers:

  • Delete the partially-written workflow file
  • Restore the original .gitignore
  • Restore the original .editorconfig
  • Delete Go module files
  • Delete the directory

You're left with a clean filesystem. Ready to retry.

Why This Matters

Consistency at Scale

Building a microservice platform? Running a SaaS with 100+ projects? Scaffolding can't be flaky. Every project should have identical structure, tooling, and configuration.

With scbake, this just works:

  • Every project has the same setup
  • No more "this service has a different linter config"
  • No more "why didn't we set up GitHub Actions here?"

Consistency becomes a non-issue. Failures get caught and rolled back.

Team Onboarding

New developer onboarding is simple. They run one command:

scbake new my-feature --lang go --with makefile ci_github go_linter
Enter fullscreen mode Exit fullscreen mode

In seconds, they've got a working project. No instructions. No checklist to verify. No manual setup.

Working on Dirty Git Trees

Most scaffolders demand a clean git state. scbake doesn't care. It can work on top of existing code:

scbake apply --with svelte_linter
Enter fullscreen mode Exit fullscreen mode

Want to add new templates to an existing project? Just run the command. If something breaks, it rolls back.

The Trade-offs

scbake isn't a silver bullet. It's good at what it does, but it has limits.

What scbake does well:

  • True atomicity. No partial failures. Everything or nothing.
  • Works on dirty git trees. Safe to apply to existing projects.
  • Composable. Mix and match templates however you want.
  • Extensible. Add custom language packs or templates.
  • Minimal dependencies. Just Cobra CLI and TOML parser.

Where it's slower:

  • Journaling overhead for rollback capability means it's slower than just copying files.
  • Still alpha-stage, so APIs might change and testing is ongoing.
  • Template structure can be complex. Extending it means understanding priority bands and handlers.

When to Use scbake

scbake shines when you're building multiple projects that need to be identical. Use it for scaffolding microservices, SaaS project generators, team environments where consistency matters, or CI/CD pipelines.

Skip it for one-off projects. If you're just copying files, use a Git template repo instead. And if every project needs custom config, scbake adds overhead without benefit.

Getting Started

scbake is available now as v0.0.1. Here's how to get started:

# Install
curl -sSL https://raw.githubusercontent.com/Emin-ACIKGOZ/scbake/master/install.sh | bash

# Create a new project
scbake new my-backend --lang go --with makefile ci_github go_linter

# Apply templates to existing project
scbake apply --with svelte_linter
Enter fullscreen mode Exit fullscreen mode

Check out the GitHub repo for docs and examples.

What's Next

This is early-stage work, and I need feedback from people who actually scaffold projects.

Some things I'm thinking about:

  • What language packs or templates are missing?
  • Do the priority bands work for your workflow?
  • Any edge cases that break atomicity?
  • What would make this actually useful for your team?

Try it. Break it. Tell me what happens. The GitHub repo is open for issues.

Baking your repositories, one transaction at a time.


Links:

Top comments (0)