# CLI

> Use the BNA UI CLI to add components to your React Native and Expo projects.

**BNA UI** — a React Native / Expo component library.
These components render through `react-native`, not the DOM: there are no HTML
elements, no Tailwind classes and no Radix primitives. Source is copied into your
project and imported through `@/components/ui/*`, `@/components/charts/*`,
`@/hooks/*` and `@/theme/*`. Colours come from the `useColor` hook rather than
hardcoded hex; sizing tokens (`HEIGHT`, `FONT_SIZE`, `BORDER_RADIUS`, `CORNERS`)
come from `@/theme/globals`.

- Docs: https://ui.ahmedbna.com/docs/cli
- Markdown: https://ui.ahmedbna.com/docs/cli.md

---

## init

Use the `init` command to initialize a new BNA project with configuration and dependencies.

The `init` command creates a new project, installs dependencies, adds utils, hooks, themes and sets up the component structure for your mobile project.

```bash
npx bna-ui init [project-name]
```

### Options

```bash
Usage: bna-ui init [options] [project-name]

Scaffold a new Expo app with BNA UI set up

Arguments:
  project-name    Name of the project, or `.` for the current directory

Options:
  --npm           Install with npm
  --yarn          Install with yarn
  --pnpm          Install with pnpm
  --bun           Install with bun
  --verbose       Print the full error stack on failure
  --skip-install  Create the project without installing dependencies
  -h, --help      display help for command

Examples
  $ bna-ui init my-app
  $ bna-ui init .                  # scaffold into the current directory
  $ bna-ui init my-app --pnpm --skip-install
```

## convex

Use the `convex` command to initialize a new BNA project with Convex backend integration.

The `convex` command creates a new project with Convex configured, installs dependencies, and sets up the backend structure.

```bash
npx bna-ui convex [project-name]
```

By default this scaffolds the full authentication setup — Google, Apple,
password and email OTP sign-in. Pass `--no-auth` for a Convex backend with no
sign-in at all: a schema, a demo query, and nothing to delete before you start.

```bash
npx bna-ui convex [project-name] --no-auth
```

See [Expo + Convex](/docs/installation/convex) and [Expo + Convex +
Auth](/docs/installation/convex-auth) for what each one gives you.

### Options

```bash
Usage: bna-ui convex [options] [project-name]

Scaffold a new Expo app with a Convex backend

Arguments:
  project-name    Name of the project

Options:
  --npm           Install with npm
  --yarn          Install with yarn
  --pnpm          Install with pnpm
  --bun           Install with bun
  --verbose       Print the full error stack on failure
  --skip-install  Create the project without installing dependencies
  --skip-convex   Skip provisioning the Convex backend
  --no-auth       Scaffold Convex without authentication
  -h, --help      display help for command

Examples
  $ bna-ui convex my-app
  $ bna-ui convex my-app --no-auth
  $ bna-ui convex my-app --skip-convex   # wire it up yourself later
```

## supabase

Use the `supabase` command to initialize a new BNA project with a Supabase
backend — Postgres, row level security, realtime, storage and edge functions.

```bash
npx bna-ui supabase [project-name]
```

By default this scaffolds the full authentication setup — password, magic links,
email OTP, Google, Apple and GitHub. Pass `--no-auth` for a backend with no
sign-in: migrations, a live query, storage and an edge function.

```bash
npx bna-ui supabase [project-name] --no-auth
```

After copying files it asks for your project URL and publishable key, writes
them to `.env.local`, and then — only if the [Supabase
CLI](https://supabase.com/docs/guides/local-development) is on your `PATH` —
links the project, applies the migrations and generates
`lib/database.types.ts`. If it is not installed, those commands are printed as
next steps instead. Nothing fails either way.

See [Expo + Supabase](/docs/installation/supabase) and [Expo + Supabase +
Auth](/docs/installation/supabase-auth) for what each one gives you.

### Options

```bash
Usage: bna-ui supabase [options] [project-name]

Scaffold a new Expo app with a Supabase backend

Arguments:
  project-name     Name of the project

Options:
  --npm            Install with npm
  --yarn           Install with yarn
  --pnpm           Install with pnpm
  --bun            Install with bun
  --verbose        Print the full error stack on failure
  --skip-install   Create the project without installing dependencies
  --skip-supabase  Skip linking the project and applying migrations
  --no-auth        Scaffold Supabase without authentication
  -h, --help       display help for command

Examples
  $ bna-ui supabase my-app
  $ bna-ui supabase my-app --no-auth
  $ bna-ui supabase my-app --skip-supabase
```

## firebase

Use the `firebase` command to initialize a new BNA project with a Firebase
backend — Cloud Firestore, Cloud Storage, and security rules with tests that
execute them.

```bash
npx bna-ui firebase [project-name]
```

By default this scaffolds the full authentication setup — email and password,
Google and Apple, onboarding and a profile. Pass `--no-auth` for a backend with
no sign-in: a live task list, storage uploads with progress, and open rules.

```bash
npx bna-ui firebase [project-name] --no-auth
```

After copying files it asks for your Firebase web config — deriving the auth
domain and storage bucket from the project ID as defaults — writes `.env.local`,
sets the default project in `.firebaserc`, and then, only if
[firebase-tools](https://firebase.google.com/docs/cli) is on your `PATH`,
selects the project and deploys the rules and indexes. If it is not installed,
those commands are printed as next steps instead. Nothing fails either way.

> The CLI cannot create a project for you. You need one with a **Web** app added
> to it, plus Firestore and Storage enabled from the console's Build menu.

See [Expo + Firebase](/docs/installation/firebase) and [Expo + Firebase +
Auth](/docs/installation/firebase-auth) for what each one gives you.

### Options

```bash
Usage: bna-ui firebase [options] [project-name]

Scaffold a new Expo app with a Firebase backend

Arguments:
  project-name     Name of the project

Options:
  --npm            Install with npm
  --yarn           Install with yarn
  --pnpm           Install with pnpm
  --bun            Install with bun
  --verbose        Print the full error stack on failure
  --skip-install   Create the project without installing dependencies
  --skip-firebase  Skip collecting the config and deploying the rules
  --no-auth        Scaffold Firebase without authentication
  -h, --help       display help for command

Examples
  $ bna-ui firebase my-app
  $ bna-ui firebase my-app --no-auth
  $ bna-ui firebase my-app --skip-firebase
```

## add

Use the `add` command to add components and dependencies to your React Native or Expo project.

```bash
npx bna-ui add [component]
```

### Options

```bash
Usage: bna-ui add [options] [components...]

Add components to an existing project

Arguments:
  components        Component names. Omit to pick interactively.

Options:
  --npm             Install with npm
  --yarn            Install with yarn
  --pnpm            Install with pnpm
  --bun             Install with bun
  --verbose         Print the full error stack on failure
  --overwrite       Replace files that already exist
  --dry-run         Show what would be written, and write nothing
  -y, --yes         Skip prompts, keeping any existing files
  --registry <url>  Registry to fetch from
  -h, --help        display help for command

Examples
  $ bna-ui add button
  $ bna-ui add button input card
  $ bna-ui add                     # browse and pick
  $ bna-ui add button --dry-run
  $ bna-ui add button --registry http://localhost:3000/r
```

### Where components come from

`add` fetches component source from `https://ui.ahmedbna.com/r` and writes it
into your project. Responses are cached under `~/.cache/bna-ui` and revalidated
with ETags, so repeat installs are fast and work offline.

Point it somewhere else with the `--registry` flag or the `BNA_UI_REGISTRY`
environment variable:

```bash
npx bna-ui add button --registry http://localhost:3000/r
```

Adding a component brings its whole dependency chain — `button` also installs
the `text`, `icon` and `spinner` it composes, the hooks and theme files they
import, and any npm packages they need.

## list

Every component, chart, hook and theme file the registry ships.

```bash
npx bna-ui list
npx bna-ui list --type chart
```

### Options

```bash
Usage: bna-ui list|ls [options]

List every component, chart, hook and theme file

Options:
  --type <type>     Narrow to ui, chart, hook or theme
  --json            Emit as JSON, for scripts and agents
  --registry <url>  Registry to read from
  --verbose         Print the full error stack on failure
  -h, --help        display help for command

Examples
  $ bna-ui list
  $ bna-ui list --type chart
  $ bna-ui list --json
```

## search

Find something without knowing its exact name.

```bash
npx bna-ui search chart
```

### Options

```bash
Usage: bna-ui search [options] <query>

Search the registry by name or description

Arguments:
  query             Search term, e.g. "chart" or "date"

Options:
  --json            Emit as JSON, for scripts and agents
  --registry <url>  Registry to read from
  --verbose         Print the full error stack on failure
  -h, --help        display help for command

Examples
  $ bna-ui search chart
  $ bna-ui search "date picker"
```

## info

A component's description, props, install command, source and examples — the
same bundle the MCP server serves. `--json` makes it machine-readable.

```bash
npx bna-ui info button
npx bna-ui info button --json
```

### Options

```bash
Usage: bna-ui info [options] <component>

Print a component's props, source and examples

Arguments:
  component         Component name, e.g. button

Options:
  --json            Emit the full bundle as JSON, for scripts and agents
  --registry <url>  Registry to fetch from
  --verbose         Print the full error stack on failure
  -h, --help        display help for command

Examples
  $ bna-ui info button
  $ bna-ui info button --json | jq .meta
```

## mcp

Runs an MCP server over stdio so an AI assistant can browse and read the
registry itself. See [MCP](/docs/mcp) for editor configuration.

```bash
claude mcp add bna-ui -- npx -y bna-ui mcp
```

The server ships as a separate package, `@bna-ui/mcp`, and `bna-ui mcp` hands
off to it. That keeps the MCP SDK — which pulls in HTTP and SSE transport
dependencies this server never uses — out of every `npx bna-ui add`.

## components.json

`init` writes one. It is optional: every command works without it, on the same
defaults. It exists so you stop repeating yourself.

```json title="components.json"
{
  "registry": "https://ui.ahmedbna.com/r",
  "aliases": {
    "components": "ui-kit"
  },
  "packageManager": "pnpm"
}
```

| Key              | Effect                                                          |
| ---------------- | --------------------------------------------------------------- |
| `registry`       | Where `add`, `list`, `search` and `info` fetch from             |
| `aliases`        | Where each kind of file is written, relative to the `@/` root   |
| `baseDir`        | Overrides where `@/` points, when the tsconfig reading is wrong |
| `packageManager` | Which manager installs npm dependencies                         |

### Where files land

`add` writes relative to whatever your `tsconfig.json` maps `@/*` onto — the
same alias every installed file imports through. Nothing to configure:

| `"@/*"` in your tsconfig | `add button` writes            |
| ------------------------ | ------------------------------ |
| `["./*"]`                | `components/ui/button.tsx`     |
| `["./src/*"]`            | `src/components/ui/button.tsx` |

`baseUrl` is honoured, and `jsconfig.json` works the same way. Set `baseDir` to
override the detection — useful when the alias is declared in a base config you
`extends` rather than in the project's own tsconfig.

### Aliases

`aliases` moves a kind of file to a different directory _inside_ `@/`, and `add`
rewrites the matching import specifiers in the source it copies so everything
still resolves. With the config above, `add button` writes `ui-kit/ui/button.tsx`
and its imports read `@/ui-kit/ui/text`. Only the leading segment is remapped —
the `ui/` beneath it is part of the registry's own layout.

Note these are relative to the `@/` root, not to the project root. In an app
whose `@/*` maps to `./src/*`, components already land under `src/` — writing
`"components": "src/components"` would nest them twice, so `add` ignores the
redundant prefix and tells you to drop it.

## Examples

### Initialize a new project

```bash
npx bna-ui init my-app
```

### Initialize with Convex backend

```bash
npx bna-ui convex my-convex-app
```

### Initialize with Supabase backend

```bash
npx bna-ui supabase my-supabase-app
```

### Initialize with Firebase backend

```bash
npx bna-ui firebase my-firebase-app
```

### Initialize using specific package manager

```bash
npx bna-ui init my-app --pnpm
```

### Skip package installation

```bash
npx bna-ui init my-app --skip-install
```

### Add a button component

```bash
npx bna-ui add button
```

### Add multiple components

```bash
npx bna-ui add button input card
```

### Add component with overwrite

```bash
npx bna-ui add button --overwrite
```

### Preview what would be installed

```bash
npx bna-ui add button --dry-run
```

### Add components without confirmation

```bash
npx bna-ui add button input --yes
```

## Package managers

Pass a flag to force one:

- `--npm`
- `--yarn`
- `--pnpm`
- `--bun`

Without a flag the CLI works it out, in this order:

1. `packageManager` in your `components.json`.
2. How you invoked it — `npx`, `pnpm dlx`, `bunx`.
3. Your project's lockfile or its `packageManager` field.
4. npm.

The scaffold commands print which one they picked.

### Why scaffolds pin a linker

Metro and React Native's autolinking both read `node_modules` off disk, so Expo
needs a real, flat one. Two package managers do not give it one by default, and
scaffolds ship the config that fixes each.

### yarn

Yarn 2+ installs [Plug'n'Play](https://yarnpkg.com/features/pnp) by default — a
`.pnp.cjs` resolver and no `node_modules` directory at all, which Metro cannot
read. Scaffolds ship:

```yaml title=".yarnrc.yml"
nodeLinker: node-modules
```

Yarn 1.x is flat already and ignores this file.

### pnpm

Scaffolds ship an `.npmrc` and a `pnpm-workspace.yaml` that both pin pnpm to the
hoisted linker:

```ini title=".npmrc"
node-linker=hoisted
```

```yaml title="pnpm-workspace.yaml"
nodeLinker: hoisted
```

Expo needs a flat `node_modules` — Metro resolves its own empty module out of
`metro-config`'s require paths, and React Native's autolinking walks
`node_modules` by hand. Under pnpm's default isolated layout `expo start` fails
with `Unable to resolve module …/metro-runtime/src/modules/empty-module.js`.
Both files ship because pnpm 11 reads settings only from `pnpm-workspace.yaml`
while pnpm 10.15 and older read only `.npmrc`.

If you have a project scaffolded before this landed, add both files and
reinstall. Clear Metro's cache on the first run — switching an existing project
from the isolated layout to the hoisted one turns `node_modules/react-native`
from a symlink into a real directory, and a warm cache fails on the change with
`TreeFS: Could not add directory node_modules/react-native`:

```bash
rm -rf node_modules pnpm-lock.yaml
pnpm install
npx expo start --clear
```
