# init and add

> Scaffold the config, the data layer and framework glue for your project.

Source: https://bettersupabase.com/docs/cli/init

```bash
npx better-supabase init   # before better-supabase is installed
pnpm better-supabase init  # once it is a dependency
```

`init` reads your `package.json` and writes:

* `better-supabase.config.ts` with `casing` written out (`--casing camel|snake`;
  `init` picks `camel` by default, while a config without `casing` means
  `snake`). It lists the integrations it set up under `integrations`, and
  carries commented `gen`, `env` and `doctor` entries for the options you
  would otherwise pass on every run (see [Flags and the config](/docs/cli/config#flags-and-the-config))
* `src/lib/supabase/index.ts`, which exports `betterSupabase` and the `Models` and `Functions` types
* glue for every framework it finds, the same files `add` writes

When `supabase/config.toml` exists and has no `[experimental.pgdelta]` table,
`init` adds one with `enabled = true`, so `supabase db schema declarative sync`
diffs your schema files with pg-delta, the engine `supabase init` uses for new
projects. A table that sets `enabled = false` stays as it is, and `init` prints
the steps to switch (see [BS316](/docs/cli/doctor#bs316)).

It then prints the next steps: the install command for your package manager,
`supabase start`, `better-supabase env` and `better-supabase gen`. Files that
already exist are never overwritten unless you pass `--force` or confirm the
prompt, and `--dry-run` shows what would be written. The names and the layout are described in [Naming](/docs/concepts/naming).

In a terminal, `init` asks for the casing (unless you pass `--casing`), the
integrations, with the detected ones checked (unless you pass `--with`), and
whether to overwrite files that exist. `add` without names asks which
integrations to add. It never asks in CI, when stdin or stdout is not a
terminal, or with `--yes`, which takes the flags and the defaults.

| Found in `package.json` | Integrations           |
| ----------------------- | ---------------------- |
| `next`                  | `next` (and `client`)  |
| `hono`                  | `hono`                 |
| `@orpc/server`          | `orpc`                 |
| `vite`, `expo`          | `client`               |
| `@tanstack/react-query` | `react` (and `client`) |

Add more with `--with edge,mcp`. A project with only `edge` and `mcp` gets no
`src/lib/supabase/index.ts`: Edge Functions import `betterSupabase` from
`supabase/functions/_shared/supabase.ts`.

## Supabase Lite [#supabase-lite]

```bash
pnpm better-supabase init --lite
```

`--lite` sets the project up for [Supabase Lite](/docs/platform/lite). The
next steps install `@supabase/lite` as a dev dependency instead of `pg`, run
`npx lite init` and `npx lite dev` instead of `supabase init` and
`supabase start`, and ask you to set `jwt_secret = "env(SUPABASE_JWT_SECRET)"`
in `supabase/config.toml` with a secret of 32 or more characters in `.env`.
Pass `backend: 'lite'` to `createServer` (or the framework adapter) so the
server verifies Lite's HS256 tokens.

## Workspaces [#workspaces]

At the root of a pnpm, npm, yarn or bun workspace (a `pnpm-workspace.yaml`,
or `workspaces` in `package.json`), `init` writes into one package instead of
the root. In a terminal it asks which package owns the runtime, with the one
that already depends on better-supabase (or else the first with a framework)
selected. Otherwise pass it:

```bash
pnpm better-supabase init --package packages/runtime
```

`init` then detects the frameworks and `tsconfig.json` of that package, writes
the config and the glue there, and prints next steps that target it:
`pnpm --filter @acme/runtime add ...` (or `npm install -w`, `yarn workspace`,
`bun add --cwd`) and `better-supabase gen --cwd packages/runtime`. Without
`--package` and without a terminal, `init` stops with an error that lists the
packages; `--package .` writes at the root as before. See
[monorepos](/docs/guides/monorepo) for how to split the runtime from domain
packages.

## add [#add]

```bash
pnpm better-supabase add hono mcp
```

`add` without an argument sets up every integration in the config's
`integrations` list whose files are missing, which is how a fresh checkout
or a new package in a workspace gets its glue. When you name integrations
the config doesn't list yet, `add` prints the `integrations` entry to paste.

| Integration | Writes                                                                                            |
| ----------- | ------------------------------------------------------------------------------------------------- |
| `client`    | `lib/supabase/client.ts` with the framework's public env variables                                |
| `next`      | `lib/supabase/server.ts` (with `import "server-only"`) and `proxy.ts`                             |
| `react`     | `providers.tsx` (`app/providers.tsx` in Next.js) and `lib/hooks.ts`                               |
| `hono`      | `server.ts`, which creates `bs` and adds the middleware and error handler                         |
| `orpc`      | `router.ts`, which creates `bs` and adds the auth middleware                                      |
| `edge`      | `supabase/functions/api` (`server.ts` creates `bs`) plus `supabase/functions/_shared/supabase.ts` |
| `mcp`       | `supabase/functions/mcp`, an MCP server as an Edge Function (`server.ts` creates `bs`)            |

Relative imports follow your `tsconfig.json`: they keep `.ts` when
`allowImportingTsExtensions` or `rewriteRelativeImportExtensions` is on.
Edge Functions always use `.ts` and get a `deno.json` import map. CI
typechecks every template against the library, so the files compile as
written. The names and the layout are described in [Naming](/docs/concepts/naming).