DEV Community

Cover image for I got tired of configuring the same stack over and over, so I built a modular project assembler
Ronak Parmar
Ronak Parmar

Posted on

I got tired of configuring the same stack over and over, so I built a modular project assembler

Every side project I started followed the same ritual.

Find a starter. Clone it. Realize it doesn't have the exact
combination I need — say, Next.js with Express as a separate
backend, PostgreSQL, JWT auth, and Tailwind. Start adding things.
Watch the tsconfig break. Spend 45 minutes on Stack Overflow.
Finally start actually building at 11pm, mentally exhausted.

I did this enough times that I started keeping a folder of
"my personal starters." Which worked until I had six of them and
they were all slightly different and none of them had the latest
versions of anything.

So I built Foundation CLI instead.


What it is

Foundation CLI is a dependency-aware project assembler. You describe
your stack — frontend, backend, database, auth, UI, deployment — and
instead of copying static template files, it:

  1. Resolves the full module dependency graph
  2. Detects and handles conflicts automatically
  3. Merges configs intelligently (deep merge for package.json, key-dedup for .env, semver intersection for requirements.txt)
  4. Commits everything atomically — or not at all

Demo

npx @systemlabs/foundation-cli create
Enter fullscreen mode Exit fullscreen mode

The part that was interesting to build

The dependency resolver was the core challenge. Modules don't
conflict by name — they conflict by capability. "Auth JWT" and
"Auth OAuth" are different implementations of the same capability.
The resolver uses capability tokens, not module IDs, to detect this.

Then it runs Kahn's algorithm to build a topological sort of the
module execution order — because if Tailwind needs to run after
Next.js (to patch the config correctly), that dependency needs to be
explicit and enforced.

Conflicts come in two tiers:

  • Hard conflicts — two auth modules, two frontends. Block the entire scaffold.
  • Advisory conflicts — Express + Cloudflare Workers (Express doesn't run on the edge). Warn, but don't block.

The config merge problem

This is the part that template copiers get wrong. When you add
Tailwind to a Next.js + Express project, three different files need
to change:

  • package.json — new devDependencies
  • tailwind.config.js — new file
  • globals.css — Tailwind directives
  • Possibly next.config.mjs — PostCSS config

A static template can't do this. You either have a template per
combination (exponential), or you have a module system that knows
how to merge.

Foundation CLI's merge engine handles this per file type. JSON files
get deep-merged with conflict detection. .env files get
key-deduplicated. docker-compose.yml gets service-merged.
requirements.txt gets semver-intersected.


Zero partial scaffolds

Every write goes through a FileTransaction. Files are staged to a
temp directory. If anything fails — a template render error, a
missing dependency, a hook failure — the temp dir is deleted and
the output directory is left completely untouched.

You either get a complete, working project or you get nothing. No
mystery half-generated directories.


What's in it

  • 28 built-in modules across 7 categories
  • 8 project archetypes (SaaS, AI App, E-commerce, API Backend, etc.) with pre-filled smart defaults
  • Plugin SDK — third-party modules publish to npm with foundation-plugin keyword
  • TypeScript throughout, strict mode, all generated projects pass tsc --noEmit

Try it

npx @systemlabs/foundation-cli create
Enter fullscreen mode Exit fullscreen mode

Repo: https://github.com/ronak-create/Foundation-Cli

I'd love feedback — especially if you've built something similar
and solved the config merge problem differently. The current
approach works but I'm not convinced it's the best design.

Top comments (0)