nodejs-scaffold
Skill1 starsChanged 37 days agoMITView on GitHub
Scaffolds a new Node.js modular-monolith REST API from scratch (no package.json yet) — Fastify, TypeBox OpenAPI, Drizzle + Postgres, JWT auth. Triggers: 'scaffold node api', 'create a fastify backend', 'new node backend'.
- Installs packages
In this repository23 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- harness-auditSkill
- skill-benchSkill
- ask-biginSkill
- bigin-harness-setupSkill
- contract-syncSkill
- debug-workflowSkill
- discovery-workflowSkill
- epic-workflowSkill
- flutter-figma-handoffSkill
- go-scaffoldSkill
- knowledge-distillSkill
- model-routerSkill
- napkinSkill
- next-scaffoldSkill
- nuxt-marketing-scaffoldSkill
- nuxt-scaffoldSkill
- nuxt-ui-figma-handoffSkill
- project-scaffoldSkill
- session-handoffSkill
- sprint-distillSkill
- task-workflowSkill
- write-testsSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 28
Add a feature, endpoint, migration, or worker to an existing Node API → task-workflow
- Very specific: line 31
Add governance files to an already-scaffolded repo → bigin-harness-setup
- Distinctive: line 37
Check the target directory:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
nodejs-scaffold
This skill is mechanical: gather config, run the script, relay its output. Do not deliberate — no thinking needed on any step here.
Scaffolds a Node.js REST API from a single template. The mechanical work is done by a deterministic script — scripts/scaffold.mjs (Node stdlib only, cross-platform, zero prompts). This skill's only jobs: decide the CLI flags, run the script, report the result. Do not perform any scaffolding steps yourself.
Stack: Node.js ≥22, Fastify (modular monolith), code-first OpenAPI via TypeBox + @fastify/swagger/@fastify/swagger-ui (route schemas generate src/api/openapi.json), per-module drizzle-orm schemas + postgres (postgres.js) + Postgres with drizzle-kit migrations, JWT (@fastify/jwt, HS256) + argon2id auth, an in-process event bus + graphile-worker job queue (outbox/inbox pattern), Idempotency-Key handling, cursor pagination, a fixed nested error contract, @fastify/cors + @fastify/rate-limit, Fastify's built-in pino logger, ESLint (flat config) with eslint-plugin-boundaries enforcing module boundaries, Vitest.
One template only — no variant menu like nuxt-scaffold's. The generated app ships two example modules proving the full architecture end-to-end: users (create/list/get + auth) and posts (which composes author_name from users through a real cross-module read — the concrete proof the module boundary and batch-get rule work, not an empty folder a lint rule passes on). Everything else about the shape is fixed.
Governance (CLAUDE.md,
.claude/rules/, AI guides,bash-guard.mjs) is not this skill's job — runbigin-harness-setupafterward to overlay it.
Prerequisites: Node.js ≥22 on PATH, pnpm on PATH (corepack enable && corepack prepare pnpm@latest --activate if missing), git. Docker isn't touched by the script (compose/Dockerfile are written but never invoked). Scaffolding is in-place into the target directory (for a brand-new project: mkdir my-api first, or pass --dir).
When not to use
This skill only ever creates a new project. A request about a Node app that already exists belongs elsewhere — even when it names this exact stack. Fastify, Drizzle, TypeBox, the outbox/inbox and the job queue are what this scaffold generates; they are not topics it owns.
- Add a feature, endpoint, migration, or worker to an existing Node API →
task-workflow - Fix a bug or a failing check →
debug-workflow - Explain how a library in the stack works → answer directly, no skill
- Add governance files to an already-scaffolded repo →
bigin-harness-setup
Step 1: Detect state & confirm
Check the target directory:
package.jsonanddrizzle.config.tsandsrc/modules/users/all exist → a complete or partial scaffold from a prior run. Ask: "This looks like an earlier nodejs-scaffold run — overwrite with --force? (yes / no)". If yes → re-run Step 3 with--force. If no → stop.package.jsonexists without those signature files → an existing project, not a prior run.--forcewould overwrite itspackage.json,README.md,tsconfig.jsonand every other template path, so never offer it. Stop and point totask-workflow(add to it) orbigin-harness-setup(govern it).- No
package.json, directory empty or doesn't exist → ask: "Scaffold a Node.js REST API here (Fastify modular monolith + Drizzle + Postgres)? (yes / no)". If no → stop. - No
package.json, but directory has other files (e.g. a README already committed) → same question, but flag that--forcewill be needed since the script refuses to write into a non-empty directory otherwise.
Step 2: Gather config
One decision matters here — everything else defaults sensibly:
- Project name (required, free text, not
AskUserQuestion— needs regex validation, not a menu) — kebab-case, e.g.orders-api. Drivespackage.jsonname, Docker image name, Postgres user/db, README/OpenAPI title. Ask directly; there's no sensible default. Node has no module-path concept, so--projectis the only required flag.
No AskUserQuestion call needed here — there's no multi-choice decision (this skill has one template, one stack). CORS origins, target directory, and commit behavior all default sensibly (see flag table below); only ask about them if the request implies a specific need (a named frontend origin, scaffolding without git, or maintainer template iteration).
Show a one-line summary and confirm, e.g. Project: orders-api · Dir: . If no → stop.
Step 3: Run the script
node ${CLAUDE_SKILL_DIR}/scripts/scaffold.mjs --project <name> [--dir <dir>] [--cors <origins>] [--force] [--no-commit] [--skip-verify]| Flag | Default | Purpose |
--project | (required) | kebab-case project name |
--dir | . | Target directory |
--cors | http://localhost:3000 | Comma-separated default CORS_ORIGINS |
--force | off | Allow writing into a non-empty directory |
--no-commit | off | Skip git init/add/commit entirely — files are written and verified but nothing is committed |
--skip-verify | off | Write files only — skip pnpm add, codegen, lint, typecheck, build, test, and commit. Maintainer-only, for fast template iteration; never set this from the normal user-facing flow. The result isn't buildable until pnpm install && pnpm db:generate && pnpm openapi:export run manually afterward. |
Stream its output — pnpm add (deps then devDeps) takes the bulk of the time on a fresh run. Every subsequent stage (codegen, openapi:export, lint, type-check, build, test, git commit) is internal — do not duplicate any of it by hand.
Step 4: Report
- Exit 0 → relay the script's "Next steps" output verbatim.
- Exit 2 → bad flags; fix per the error message and re-run.
- Exit 1 → runtime failure; the last
[scaffold] ERROR:line names the failing command (commonly: pnpm not on PATH, Node <22, or a network failure duringpnpm add). Fix the cause and re-run with--force— files from the failed attempt were already written.
Maintainer notes (design rationale, manual validation after changing the script or templates) live in references/MAINTAINING.md. A scaffold run never needs them, so it never reads them.
References
scripts/scaffold.mjs— the scaffold implementation (single file, Node stdlib only). Discovers template files by recursively walkingscripts/templates/files/and writes them all in one pass (no STATIC/GLUE split — code-first OpenAPI removed the ordering dependency), then runspnpm add→drizzle-kit generate→openapi:export→ lint/type-check/build/test → commit. Never runspnpm test:integrationitself (see the testing design note above).scripts/templates/files/— source of truth for every file written into the project.src/api/openapi.jsonanddrizzle/*.sqlare NOT here — they're generated during the run and committed.tests/global-setup.tsandvitest.integration.config.tsare the testcontainers wiring forpnpm test:integration;scripts/seed.tsbackspnpm dev:setup.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

