How I Built a CLI That Generates 12 Project Templates in 30 Seconds
When I started building ScaffoldX, I had a simple goal: create a CLI tool that generates production-ready project templates in seconds — not minutes.
After 3 weekends of iteration, I got it working. Here's how.
The Problem
Most project scaffolding tools suffer from two problems:
- They're slow. Even "fast" generators take 10-30 seconds to output code.
- They're opinionated. You get exactly what they give you — no customization.
I needed something that was both fast and flexible.
Architecture Overview
// scaffoldx-cli/src/index.js
import { Command } from 'commander';
import { generateProject } from './generator.js';
import { loadConfig } from './config.js';
const program = new Command();
program
.name('scaffoldx')
.description('Generate project templates in seconds')
.argument('[name]', 'project name')
.option('-t, --template <type>', 'template type (react, node, typescript)')
.action(async (name, options) => {
const config = loadConfig(options.template);
await generateProject(name, config);
console.log('✅ Done in <1s');
});
program.parse();
Three core components:
- Command parser — Commander.js for CLI interface
- Generator — Template rendering engine
- Config loader — Customizable project configs
Step 1: Template System
The key to speed is pre-compiled templates. I use EJS with a smart caching layer:
// scaffoldx-cli/src/generator.js
import ejs from 'ejs';
import fs from 'fs/promises';
import path from 'path';
const templateCache = new Map();
export async function generateProject(name, config) {
const template = await getTemplate(config);
const output = ejs.render(template, {
project: name,
version: config.version,
dependencies: config.dependencies
});
await fs.writeFile(
path.join(process.cwd(), name, 'README.md'),
output
);
}
async function getTemplate(config) {
const key = config.template;
if (!templateCache.has(key)) {
const template = await fs.readFile(
path.join(__dirname, 'templates', key, 'template.ejs'),
'utf-8'
);
templateCache.set(key, template);
}
return templateCache.get(key);
}
Cache prevents re-reading templates on every call. Result: ~30 seconds for 12 templates.
Step 2: Config System
// scaffoldx-cli/src/config.js
export function loadConfig(template = 'typescript') {
const configs = {
react: {
version: '1.0.0',
dependencies: ['react', 'react-dom'],
devDependencies: ['vite', 'typescript']
},
node: {
version: '1.0.0',
dependencies: ['express'],
devDependencies: ['ts-node', 'typescript']
},
typescript: {
version: '1.0.0',
dependencies: [],
devDependencies: ['typescript', '@types/node']
}
};
return configs[template] || configs.typescript;
}
Users can override any config via a .scaffoldx.json file in their project root.
Step 3: The Magic — 12 Templates
Here are the 12 templates ScaffoldX generates:
| # | Template | Use Case |
|---|---|---|
| 1 | TypeScript | Pure TS projects |
| 2 | React | React + Vite |
| 3 | Next.js | Full-stack React |
| 4 | Node.js | Express API |
| 5 | Svelte | SvelteKit |
| 6 | Vue | Vue 3 + Vite |
| 7 | Nuxt | Nuxt 3 |
| 8 | Angular | Angular CLI |
| 9 | Remix | Full-stack React |
| 10 | Astro | Static sites |
| 11 | React Native | Mobile apps |
| 12 | Deno | Deno projects |
Each one is production-ready, with proper TypeScript config, linting, and testing setup.
Step 4: Testing
// scaffoldx-cli/src/__tests__/generator.test.js
import { generateProject } from '../generator.js';
import fs from 'fs/promises';
jest.mock('fs/promises');
describe('generateProject', () => {
it('should generate project files', async () => {
await generateProject('test-project', { template: 'typescript' });
expect(fs.writeFile).toHaveBeenCalledWith(
expect.stringContaining('test-project'),
expect.stringContaining('typescript')
);
});
});
The Result
$ npx scaffoldx-cli my-app
✅ Done in <1s
That's it. No create-react-app, no npm init, no waiting 5 minutes. Just npx scaffoldx-cli and you're done.
Why This Matters
Every project I start, I used to spend 15-30 minutes on setup:
- Install packages
- Configure TypeScript
- Set up linting
- Create folder structure
- Write initial boilerplate
Now it's 30 seconds. That's 15-30 minutes saved per project.
For a developer who starts 10 projects a month, that's 5-8 hours saved. For a team, it's 100+ hours/month.
Get ScaffoldX
npm i scaffoldx-cli
npx scaffoldx-cli my-app
Open source. Free. No bloat.
👉 GitHub: wuchunjie00/scaffoldx
What's Next
I'm adding:
- Custom template support (your own configs)
- Plugin system (community templates)
- Better error handling
Want to contribute? PRs welcome.
#javascript #typescript #node #cli #opensource #tutorial
Top comments (1)
That's great work!
Your work is high level so I gave it a star on GitHub✨ !
Good job 👏.