Every project scaffolder I've used works the same way. You pick a template, it copies a folder, and you start deleting what you didn't want.
Atarashi v0.6 worked that way too. It had five template folders. Then the obvious problem showed up: every new combination of framework, database and ORM meant another folder to write and maintain. Fastify with Postgres and Drizzle? New folder. Same thing with Prisma? Another one. The number of folders grows with every option you add, and none of them is ever quite what you wanted.
So for 1.0 I threw the template engine out and rebuilt it around composition.
The problem with templates
A template folder is a snapshot of one set of decisions. Two things go wrong with that.
First, you can't change one decision without hand-editing generated code. Want Hono instead of Express? You're now rewriting the template's output by hand.
Second, nothing records what you chose. Three weeks later you want structured logging, and the scaffolder can't help, because it has no idea what your project is made of.
Blueprints instead of folders
Atarashi 1.0 builds a project out of small units called blueprints. There are 36 of them: HTTP frameworks (express, fastify, hono), databases (postgres, mysql, mongodb, sqlite), ORMs (drizzle, prisma, mongoose), auth, testing, linting, docker, CI, and React, Angular and Next front ends.
The important part: blueprints never name each other. They declare capabilities.
{
"id": "orm/drizzle",
"provides": ["orm", "orm:drizzle"],
"requires": ["database:sql"],
"conflicts": ["orm"]
}
Drizzle doesn't know about Postgres. It says "I need a SQL database", and anything that provides database:sql satisfies it. That one indirection is what makes every combination work without a template for it.
It refuses things that can't work
Because every blueprint declares what it needs and what it conflicts with, Atarashi can check the whole plan before it writes a single file.
Ask for Drizzle with no database:
$ atarashi new my-api --add orm/drizzle
✖ orm/drizzle requires `database:sql`, and 3 blueprints provide it
→ Add `--add db/mysql` to choose it
→ Add `--add db/postgres` to choose it
→ Add `--add db/sqlite` to choose it
Ask for two databases:
$ atarashi new my-api --add db/postgres --add db/mongodb
✖ Cannot combine db/mongodb with db/postgres: both claim `database`, and only one is allowed
→ Remove one of them: `--remove db/postgres`
No half-generated directory to clean up. And when exactly one blueprint can satisfy a requirement, it gets added for you. Pick Fastify and it pulls in validation/zod, because the env config needs it:
$ atarashi new my-api --http fastify --db postgres --orm drizzle --auth jwt
✔ Created my-api
14 files · 14 dependencies · npm
+ validation/zod (required by http/fastify → config:env)
It remembers what you chose
Every generated project gets an atarashi.json:
{
"name": "my-api",
"blueprints": [
{ "id": "core/node-ts", "version": "1.0.0" },
{ "id": "validation/zod", "version": "1.0.0" },
{ "id": "db/postgres", "version": "1.0.0" },
{ "id": "orm/drizzle", "version": "1.0.0" },
{ "id": "http/fastify", "version": "1.0.0" },
{ "id": "auth/jwt", "version": "1.0.0" }
],
"answers": {
"auth.expiry": "7d",
"db.name": "my-api",
"db.pool": true
}
}
This is what templates are missing. Because the project knows what it's made of, you can keep adding to it later:
$ atarashi add obs/pino
Adding obs/pino to my-api
· .env.example (update)
· atarashi.json (update)
· package.json (update)
· src/config/env.ts (update)
+ src/lib/logger.ts (new)
✔ Added obs/pino
add re-renders only what the new blueprint contributes and splices it into your existing files. Files you've edited by hand are never silently overwritten.
The same file also makes generation reproducible: atarashi new --from atarashi.json gives you a byte-identical project (generated secrets in .env are the exception, on purpose).
The bar every project has to clear
A generated project has to install, build, lint, test, boot and answer GET /health with no edits from you. If a combination can't hit that, it's a bug.
A few other things I cared about:
-
--dry-runprints the plan and writes nothing - it works offline, the blueprints ship inside the package
- nothing it generates depends on Atarashi, and
atarashi ejectcuts the last link - third-party blueprints use the same format and validator as the built-in ones. Publish one as
atarashi-blueprint-*on npm and anyone can use it
Try it
The fastest way is a preset, a set of blueprints known to work together:
npx atarashi@latest new my-api --preset backend-ts --yes
cd my-api && pnpm dev
backend-ts is Express, Postgres, Drizzle, JWT and Docker with strict TypeScript. There are six presets in total, from backend-minimal to fullstack-react. Or pick pieces yourself:
npx atarashi@latest new my-api --http hono --db sqlite --orm drizzle --tests vitest --lint biome
Or run atarashi with no arguments for the wizard.
What I want to hear
It's 1.0 but brand new. The most useful thing you can tell me is which combinations break: a set of flags that should work but gets rejected, or a generated project that doesn't build. There's a pinned tracking issue for exactly that.
Top comments (0)