npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dunx/create-app

v3.4.1

Published

Scaffold a new dunx application - bunx @dunx/create-app my-api

Readme

@dunx/create-app

Scaffolds a new dunx application.

bunx @dunx/create-app my-api

bun create dunx-app does not work and is not advertised: bun create <template> resolves the unscoped npm package create-<template>, which this package - being scoped - is not.

cd my-api
bun install
bun run dev       # http://localhost:3000/greetings, restarting on a change

The questions

There is no flag for choosing features. The command opens a list:

? Features  2 chosen, 1 pulled in
  ○ notes       CRUD routes with zod validation. The smallest real feature.
  ◉ openapi     OpenAPI 3.1 from the routes own schemas, plus the Swagger UI page.
  ◈ database    drizzle over bun:sqlite, with a schema, seeds and migrations.
❯ ◉ users       A repository, a service and validated routes over the database.
  ○ auth        better-auth mounted, with SessionGuard and an audit trail.
  database comes along as a requirement.
  Space toggles. ↑↓ moves. a all, n none. Enter continues.

| Key | Does | | --------------- | --------------------------------------------- | | , k j, Tab | Move the cursor | | Space | Toggle the feature under it | | a / n | Everything / nothing | | Enter | Take the selection | | Ctrl+C, Esc | Stop, having written nothing |

is chosen, is pulled in by something else you chose, is neither. The two lines under the list update as you go: one shows what your selection drags in, the other shows which of it needs Redis or Postgres running to do anything.

After the list, one more question: whether to compile the app to a single standalone binary. Yes adds a scripts/build.ts and a build script, so bun run build writes one executable with bun build --compile that a host runs with nothing installed. It needs Bun >= 1.4.1, the floor the generated package.json already declares.

Three more questions appear only when there is something to ask: a directory, when the command line named none; a package name, when the directory's is one npm would reject; and whether to write into a directory that already has files in it.

Options

| Flag | Default | Meaning | | --------------- | ------------------ | --------------------------------------------- | | --name <name> | the directory name | Package name for the generated app | | --force | off | Write into a directory that already has files | | --yes, -y | off | Skip the questions, take the minimal template | | --help | | Print usage |

Piped, redirected or in CI it asks nothing. It writes the minimal template instead, so a script never hangs on a question nothing can answer. To choose features without a terminal, call scaffold rather than passing flags.

The name is validated against npm's rules before anything is created, because an invalid one would otherwise surface as a confusing bun install failure inside a directory you just made.

Scaffolding into a repo you already made

mkdir my-api && cd my-api && git init
bunx @dunx/create-app .

.git, .gitkeep, .DS_Store and LICENSE do not count as contents, so a fresh repo or a clone of an empty GitHub repository is a valid target without a question. Nothing else is ignored: .gitignore and README.md both come out of the template. Overwriting your copy of either is what the last question asks about.

What a composed app looks like

my-api/
  src/
    main.ts          exports createApp, and serves it when run directly
    app.module.ts    the root module, importing every feature
    config.ts        one validation function, flat env in and a shaped object out
    users/           one directory per feature you chose
  package.json       dev, start, test, typecheck
  bunfig.toml        the transform preload

Three files are generated for the selection, and the feature directories are just copied. main.ts is one file rather than two: a test imports createApp from it, and the import.meta.main block at the bottom stops that same import from starting a server.

There is no worker entry point, even with queues. QueueModule is given consume: true, so the container opens the bullmq workers at onInit and closes them before the connections the handlers use. A handler marked background: true is forked by bullmq itself into src/jobs/jobs.processor.ts.

What it generates

The minimal template is the same app as examples/minimal: a service, a controller, a module, HttpFactory.create, one test against a real server, and the bunfig.toml preload line that makes constructor injection work.

Its src/ is a byte-for-byte copy of that example. A test in this package fails if the two ever drift.

Every app also gets an AGENTS.md naming its layout, its commands and the rules dunx fails at boot over, plus a CLAUDE.md pointing at it. Both link https://dunx.win/setup.md, which is served per release, rather than copying the framework's own instructions into your repository.

The example is the one CI boots, so keeping them identical makes the template trustworthy rather than merely plausible.

Two details

Versions are resolved at run time rather than written into the template. Every @dunx/* range in the template manifest is __DUNX_VERSION__, replaced with a caret range on this package's own version. dunx versions in lockstep - every package shares one number and ships together - so the version doing the scaffolding is by definition a set that works together.

Writing versions into the template would go stale on the next release.

Keep it that way when you add a package later. The packages peer-depend on each other by caret range, so mixing minors warns on install - and can leave two copies of @dunx/core in one tree, which breaks dependency injection outright: a token is a class object, so two copies are two different classes and a provider bound against one is invisible to the other.

The template's .gitignore ships as _gitignore. npm renames a published .gitignore to .npmignore, which would leave every scaffolded app without one. The scaffolder puts the dot back on write.

Programmatic use

import { scaffold } from '@dunx/create-app';

const { directory, files } = await scaffold({
  target: 'my-api',
  name: '@acme/my-api',
  features: ['users', 'openapi'],
});

This is the scripted path the removed --with flag used to be. features takes the same names the list shows, in any order, and pulls in what they require. FEATURES exports the set. Omitting it writes the minimal template. binary: true adds the standalone-binary build, and forces the generation path so it works with no features too.

scaffold throws ScaffoldError for anything the caller can fix - an unknown template, an unusable package name, a non-empty target without force - and lets everything else propagate.