Tooling

CLI

Create projects from the starters, add apps and modules, and install Frigear modules with @frigear-nu/cli.

The Frigear CLI saves you from copying and renaming starters by hand. It creates a project from a starter, adds an app or a module to a pnpm workspace, and installs Frigear modules in an app. It works in any pnpm workspace, not only in the Frigear repository. Its package is @frigear-nu/cli, a citty CLI published to npm.

Run it

Run it without installing it:

pnpx @frigear-nu/cli --help
pnpx @frigear-nu/cli <command> --help

pnpm create frigear-app (or npm create frigear-app@latest) does the same as init below.

Inside the Frigear repository, use the root cli script. It runs packages/cli/bin/cli.mjs, which loads the TypeScript source with jiti, so there is no build step:

pnpm cli --help
The starters and app templates are downloaded from the Frigear-nu/frigear-nu GitHub repository with giget. While that repository is not public, set GIGET_AUTH to a GitHub token that can read it, for example GIGET_AUTH=$(gh auth token).

Commands

CommandPurpose
initCreates a new project from a starter.
app:createAdds an app from a starter to apps/<name> of a workspace.
module:createScaffolds a new Nuxt module under packages/.
addInstalls Frigear modules in a Nuxt app and adds them to its nuxt.config.

Every command takes --cwd <dir> (default: INIT_CWD, else the current directory).

init

pnpx @frigear-nu/cli init [dir] [--platform <platform>] [-t <template>] [--ref <ref>] [--force] [--no-install]
ArgumentDefaultPurpose
dirfrigear-appDirectory to create. Its name becomes the root package.json name.
--platform, --starterasked, web when not interactiveWhat to build: web, mobile or web,mobile, or the starter's name. See the table below.
-t, --templateAny giget source to copy instead of a starter, for example gh:org/repo/path#ref. Not together with --platform.
--refmainBranch or tag of the repository to copy the starter from.
--forcefalseWrite into a directory that is not empty.
--no-installSkip pnpm install and pnpm prepare:env.
--platformStarter (also accepted as the value)What you get
webworkspaceapps/web with sign-in, account pages and user management in the admin area
mobilemobileapps/mobile, a Capacitor app that signs in at an existing issuer
web,mobilemobile-standaloneboth, with apps/web as the app's OAuth server and API

With -t, the root package.json is still renamed (when there is one), and pnpm prepare:env only runs when the template has that script.

app:create

pnpx @frigear-nu/cli app:create <name> [--template <template>] [--ref <ref>] [--no-install]
ArgumentDefaultPurpose
namerequiredFolder under apps/, kebab-cased.
--templatewebweb (the workspace starter's app), web-standalone (the mobile-standalone starter's OAuth server app) or mobile.

It needs a pnpm-workspace.yaml above --cwd. The package is named <scope>/<name>, with the scope of the existing apps (@workspace in the starters), else of the root package. It fails when apps/<name> already has a package.json, and runs pnpm install at the root unless --no-install is passed.

module:create

pnpx @frigear-nu/cli module:create <name> [--template <template>] [--scope <scope>] [--dir <dir>]
ArgumentDefaultPurpose
namerequiredName of the module, for example my-module. It is kebab-cased.
--templategh:nuxt/starter#moduleA giget template source, for example gh:github.com/my/package.
--scopethe root package's scopenpm scope, for example @acme. --scope "" leaves the name unscoped. In this repository the root is @frigear-nu/root, so modules are @frigear-nu/<name>.
--dirpackagesWorkspace folder to create the module in.

It downloads the template into <workspace root>/<dir>/<name> and sets the name in its package.json. It exits with an error, without changing anything, when that folder already contains a package.json.

add

pnpx @frigear-nu/cli add <module...> [--app <app>] [--no-install]
ArgumentDefaultPurpose
modulerequiredOne or more modules: forms means @frigear-nu/forms; a scoped name is used as is.
--appsee belowThe app: a path, or a folder under apps/.
--no-installOnly edit nuxt.config.

Without --app, the app is the current directory when it has a nuxt.config, else the only app under apps/ with one. The command runs pnpm add in the app and adds each module to modules once. It prints each module's documentation link.

Module options and the migration are still yours. A module that adds tables needs pnpm db:generate, as Adding modules describes.

create-frigear-app

pnpm create frigear-app [dir] [--platform <platform>] [-t <template>] [--ref <ref>] [--force] [--no-install]
npm create frigear-app@latest [dir] [--platform <platform>]

packages/create-frigear-app is what pnpm create and npm create find. It has no dependencies: it runs init of @frigear-nu/cli@latest with the package manager that started it (pnpm dlx, npx, yarn dlx or bunx), so it takes the same arguments as init, and every CLI release reaches it without releasing create-frigear-app. The starters come from main unless you pass --ref. Set FRIGEAR_CLI to run another CLI, such as @frigear-nu/cli@0.1.0 or a packed tarball.

After module:create in the Frigear repository

The command only creates the package. Scaffold a module starts the path through the rest: the folder layout, setup(), tests, the release config and the module page.

Developing the CLI

The source is in packages/cli/src, with one file per command in commands/. Its tests run against the repository's own .starters/, with giget mocked, so nothing is downloaded or installed:

pnpm --filter @frigear-nu/cli test

The published package is built with unbuild into dist/, and publishConfig points bin at dist/cli.mjs. It is released like every other package.

Next steps

Copyright © 2026