Skip to content

Search docs

Jump between documentation pages.

Browse docs

Scaffold a project

create-daloy is the official project generator. It scaffolds a working DaloyJS app in seconds, no copy-pasting from the docs.

Package link: create-daloy on npm. The generated apps install the framework from @daloyjs/core on npm.

One generator, five templates
generatorcreate-daloypnpm create daloy@latest my-api
defaultnode-basic@daloyjs/core/node
serverlessvercel@daloyjs/core/vercel
edgecloudflare-worker@daloyjs/core/cloudflare
runtimebun-basic@daloyjs/core/bun
runtimedeno-basic@daloyjs/core/deno
Pick a target with --template. Every starter ships the same guardrail-first posture and scripts, only the runtime adapter and config differ.

Quick start

bash
# pick the package manager you actually use
pnpm create daloy@latest my-api
npm  create daloy@latest my-api
yarn create daloy           my-api
bun  create daloy           my-api

The CLI is interactive when arguments are missing. It will ask for a project name, a template, a package manager (skipped for deno-basic), whether to install dependencies, whether to initialize a git repository, and whether to add the GitHub security bundle. The dependency-install prompt defaults to no for pnpm projects so you can review the generated .npmrc and pnpm-workspace.yaml guardrails before the first install. Other package managers default to yes.

The interactive prompts
  1. 01Project namemy-api
  2. 02Templatenode-basic, vercel, ...
  3. 03Package managerpnpm, npm, yarn, bun
  4. 04Install deps?--install / --no-install
  5. 05Init git?--git / --no-git
  6. 06GitHub security bundle?--with-ci
When you omit flags the CLI prompts for each choice in order. Pass --yes to accept every default and skip the prompts entirely. With --yes the CLI uses node-basic, the package manager that launched it (pnpm when it cannot tell), no dependency install, no git init, the GitHub security bundle enabled, and the deploy starter enabled with it.

Non-interactive usage

bash
pnpm create daloy@latest my-api --template node-basic --package-manager pnpm --with-ci --code-owner @acme/security --install --git

Flags

  • --template <name>: node-basic (default), vercel, cloudflare-worker, bun-basic, or deno-basic.
  • --package-manager <pm> (alias --pm): pnpm, npm, yarn, or bun. Defaults to the package manager that launched the CLI (so npm create daloy picks npm), and to pnpm when it cannot tell.
  • --list-templates: print available templates with descriptions.
  • --install / --no-install: install dependencies after scaffolding. The prompt defaults to no for pnpm projects and yes for npm, Yarn, and Bun projects. With --yes (or without a TTY) nothing is installed unless you pass --install.
  • --git / --no-git: initialize a git repository. The prompt defaults to yes. With --yes (or without a TTY) no repository is created unless you pass --git.
  • --minimal: strip the bookstore demo and the auto-mounted /docs + /openapi.json API docs routes so the scaffold only ships the framework bootstrap and a health route. Useful when you want to start from the smallest possible app.
  • --with-ci / --no-ci: add hardened GitHub Actions, Dependabot, CODEOWNERS, SECURITY.md, and lockfile-source verification. Defaults to yes.
  • --with-deploy / --no-deploy: add or skip the manual-only starter .github/workflows/deploy.yml. Defaults to the same value as --with-ci.
  • --code-owner <owner>: replace the CODEOWNERS placeholder when --with-ci is used, for example @acme/security.
  • --force: overwrite an existing non-empty directory.
  • --yes: accept all defaults. Never prompt.

Missing-tool hints

Before printing the completion summary, the CLI checks whether the runtime and package manager your selections actually need are on your PATH. If something is missing, it prints an official install link next to the next steps instead of leaving you to hit a command not found on your first command. For example, scaffolding the bun-basic template on a machine without Bun surfaces a https://bun.sh link, and choosing pnpm without pnpm installed surfaces https://pnpm.io/installation. Node-flavored templates (node-basic, vercel, cloudflare-worker) point at https://nodejs.org when Node.js is absent. The probe only reads PATH (it never executes the binary), and if you asked to install dependencies but the chosen package manager is missing, the CLI skips the doomed install and shows the link instead. When every required tool is present, no hint is printed.

The CLI also checks versions. npm create daloy and npx will run the scaffolder on an old Node.js because engines are only advisory there, so the CLI verifies it itself: if you are on a Node.js older than 24, it stops before scaffolding with a clear message, the nodejs.org link, and a nudge toward a version manager (nvm, fnm, Volta) rather than generating a project your runtime cannot run. And when you pick npm, it detects an npm older than 12 up front, tells you to run npm install -g npm@latest, and skips the automatic install so you get a readable explanation instead of npm's raw EBADENGINE error partway through.

Templates

Run create-daloy --list-templates to inspect the available starters without creating a project.

node-basic

A production-ready Node.js HTTP server using @daloyjs/core with secureHeaders, requestId, rateLimit, hardened install settings (pnpm-workspace.yaml plus an .npmrc mirror), a sample GET /healthz route, a contract-first GET /books/:id route with Zod validation, and Hey API codegen wired to pnpm gen.

Like FastAPI, every scaffolded project also exposes API documentation out of the box in development: /docs serves a Scalar API reference UI and /openapi.json serves the live OpenAPI 3.1 spec generated from your route definitions. Templates set docs: "auto", so a production deploy does not publish them unless you set docs: true. The dev server logs both URLs at startup. Pass docs: { ui: "swagger" } on the App constructor to switch to Swagger UI instead (the object form also stays off in production unless you add enabled: true).

cloudflare-worker

A minimal Cloudflare Worker using @daloyjs/core/cloudflare with wrangler.toml ready to deploy, secureHeaders + requestId + a per-isolate rateLimit enabled by default, a smaller edge-friendly body limit (256 KiB versus 1 MiB in the Node starter), and a Zod-validated route exposed as fetch.

vercel

A Vercel API on the Node.js runtime (Vercel's recommended runtime for standalone functions) using @daloyjs/core/vercel with a single api/index.ts function exporting toFetchHandler(app) (plus a vercel.json rewrite so DaloyJS routes at the site root), a dev script that serves the same app locally with node --watch src/dev.ts, a deploy script that runs vercel deploy, secureHeaders + requestId + a per-instance rateLimit enabled by default, a smaller serverless-friendly body limit (256 KiB), and the same health and bookstore examples as the Node starter.

The Vercel template also ships /docs (Scalar API reference) and /openapi.json wired to the same app with docs: "auto", so they are served locally but not on a production deployment (the app sets production from NODE_ENV). Set docs: true to publish them on the deployed URL.

bun-basic

A Bun runtime starter using@daloyjs/core/bun. Ships bun --hot for instant reloads, bun test for the test runner, the same starter security middleware as the Node template (secureHeaders / requestId / rateLimit), the bookstore demo route, and Hey API codegen wired through bun run gen:openapi +bun run gen:client.

deno-basic

A Deno runtime starter using@daloyjs/core/deno. Ships a deno.json with deno task dev, deno task start, deno task test, deno task contract, and deno task gen:openapi tasks, maps @daloyjs/core to the JSR package jsr:@daloyjs/daloy and Zod to an npm: specifier in the import map, and runs the server with only --allow-net and an --allow-env scoped to PORT, DENO_ENV, TRUST_PROXY_HOPS, and PUBLIC_URL. The CLI skips Node-style installs for this template, there is no package.json to patch.

Minimal scaffolds

Pass --minimal to drop the bookstore demo route and the built-in /docs + /openapi.json API docs routes from any template that supports them. The scaffolded app is left with the framework bootstrap and a single /healthz route, which is the smallest realistic starting point for teams that already know exactly what they want to build:

bash
pnpm create daloy@latest my-api --template node-basic --minimal --yes

Sentinel comments (// daloy-minimal:strip-start <tag> /// daloy-minimal:strip-end <tag>) survive a default scaffold so you can re-run the generator with --minimal later, or delete the marked blocks by hand.

Hardened CI/security bundle

The bundle is on by default (the prompt defaults to yes; pass --no-ci to skip it, or --with-ci to choose it non-interactively). It gives the new project GitHub-side supply-chain guardrails as well as runtime defaults. Node-style templates get CI, a manual-only deploy starter, CodeQL, OpenSSF Scorecard, zizmor, Dependabot, CODEOWNERS, SECURITY.md, and a lockfile-source verification script. The Deno template gets the same governance and scanning files with a Deno-native CI workflow. No template gets an npm publish workflow, because create-daloy scaffolds REST API services rather than reusable libraries.

bash
pnpm create daloy@latest my-api --template node-basic --package-manager pnpm --with-ci --code-owner @acme/security

The generated workflows use top-level permissions: {}, pinned third-party actions, harden-runner, persist-credentials: false, disabled install scripts, and no package-manager cache. Replace the CODEOWNERS placeholder if you did not pass --code-owner, then enable branch protection, required status checks, secret scanning, and push protection in GitHub settings. Use --with-ci --no-deploy when you want governance without deployment scaffolding, or --with-deploy --no-ci when you only want the deployment starter.

Editor MCP integration

Every scaffold ships a .vscode/mcp.json that wires VS Code (and other MCP-aware editors) to the DaloyJS documentation MCP server at https://daloyjs.dev/mcp over HTTP. With it, AI assistants in your editor can pull current DaloyJS docs while you work, with no manual setup. The file is authored as _vscode/mcp.json in the template and renamed to .vscode/mcp.json on copy so it survives npm packing.

json
{
  "servers": {
    "daloyjs-docs": {
      "type": "http",
      "url": "https://daloyjs.dev/mcp"
    }
  }
}

Delete the file or remove the server entry if you do not want the integration. It is editor configuration only and the framework does not depend on it at runtime.

Which template should I choose?

  • Choose node-basic for a traditional REST API on Node, Docker, Fly.io, Railway, Render, or any VM/container host.
  • Choose vercel when Vercel is your deployment target and you want a catch-all Vercel Functions API route (Node.js runtime) from the first commit.
  • Choose cloudflare-worker only when your deployment target is Cloudflare Workers. The template supports that runtime. Cloudflare is optional.
  • Choose bun-basic when your team already runs on Bun and wants bun --hot + bun test in the box.
  • Choose deno-basic when you want a runtime-native Deno project with deno task scripts, an import map, and Deno's permission flags.

Why a generator?

DaloyJS is a backend framework, so the first ten minutes matter. The scaffolder gives every project the same guardrail-first posture, the same TypeScript baseline, and the same scripts so an AI coding agent or a new teammate can navigate it without a tour. Every starter includes secureHeaders, requestId, and rateLimit. The Vercel and Cloudflare starters also set a tighter body limit.

The CLI itself ships with zero runtime dependencies: only Node built-ins, so the supply-chain story stays clean. Templates are copied verbatim from the package's templates/ directory and never run scripts during scaffolding. When you choose pnpm, the generated app keeps the hardened .npmrc and pnpm-workspace.yaml, and the CLI adds a pnpm >= 11 floor to engines (pnpm always enforces engines.pnpm). older pnpm silently ignores minimumReleaseAge, which would disable the 24h supply-chain cooldown. The CLI also warns up front if the installed pnpm is older. When you choose npm, the CLI adds an npm >= 12 floor to engines and swaps in an npm-native .npmrc with engine-strict=true (so that floor is a hard install-time failure rather than a warning), ignore-scripts=true, and min-release-age=1 (one day). Yarn and Bun scaffolds drop the pnpm-specific config so installs stay warning-free and get their own equivalents instead: Yarn gets .yarnrc.yml and .yarnrc (see the table below), and Bun gets a bunfig.toml with a 24-hour minimumReleaseAge. When you choose --with-ci, it also adds the GitHub-side security files that a company repo normally has to assemble by hand.

Install hardening per package manager (1.5.4)

From 1.5.4 every package manager gets lifecycle scripts off and a release-age cooldown where the tool supports one:

Package managerFileWhat it sets
pnpmpnpm-workspace.yaml (pnpm 11 reads it; .npmrc mirror for older tooling)ignoreScripts: true, minimumReleaseAge: 1440, blockExoticSubdeps: true, store verification
npm.npmrcignore-scripts=true, min-release-age=1 (days), engine-strict=true
Yarn.yarnrc.yml (Yarn 2+), .yarnrc (Yarn 1)enableScripts: false and npmMinimalAgeGate: "1d"; Yarn 1 gets ignore-scripts true (it has no release-age setting)
Bunbunfig.tomlminimumReleaseAge = 86400 (seconds, Bun 1.3+)

Template Dockerfiles also pin their base images by digest, so a retagged base image cannot change what your container build pulls; update the digest deliberately (Dependabot can do it with the --with-ci bundle).

Blocking lifecycle scripts stops install-script payloads, not a payload that runs when your code imports a package. The cooldown helps only against bad versions that are caught within the window. See Supply-chain security for what each control covers.

Next

After scaffolding, jump straight to Getting started for the route walkthrough, or Security for the guardrails and middleware the scaffold installed.