---
title: First Project
description: Scaffold, inspect, install, configure, and run a Better Fullstack project end to end.
translationStatus: pending
updated: 2026-08-22
---

This walkthrough creates a project, previews what the CLI generates, and shows where to look once the scaffold finishes.

## 1. Create a project

```npm
npm create better-fullstack@latest my-app
```

Accept the defaults for a TypeScript starter, or change the prompts to match the stack you want. The default stack is TanStack Router, Hono, Bun, SQLite, Drizzle, Better Auth, and tRPC in a Turborepo workspace.

## 2. Preview without writing

Add `--dry-run` to inspect the generated file tree before anything lands on disk:

```npm
npm create better-fullstack@latest my-app -- --dry-run
```

Do this before trying a new ecosystem, deployment target, or multi-ecosystem stack.

## 3. Scaffold from a template

A complete template with `--yes` makes the scaffold repeatable. This example creates the Next.js, tRPC, Prisma, PostgreSQL, and Better Auth T3 stack, then skips install and Git so you can review files first:

```npm
npm create better-fullstack@latest my-app -- \
  --template t3 \
  --yes \
  --no-install \
  --no-git
```

<Callout kind="info" title="Prompt behavior">
`--yes` accepts every remaining template value without prompting. It conflicts with core stack flags such as `--frontend`, `--backend`, and `--database`. For a custom prompt-free stack, use a complete `bts.jsonc` with `--config`.
</Callout>

[CLI Create](/docs/cli/create/) lists every flag, the `--template` presets, and `--shape` shortcuts for frontend-only, backend-only, and mobile projects.

## 4. Install dependencies

If you used `--no-install`, install inside the project with your package manager:

```bash
cd my-app
```

```npm
npm install
```

Language-native ecosystems use their own tools: `cargo build`, `uv sync --extra dev`, `go mod tidy`, `./mvnw test`, `./gradlew test`, `mix deps.get`, or `dotnet restore`. The generated README names the right one.

## 5. Configure environment variables

Every generated project includes a `.env.example` for the integrations in your stack. Copy it to `.env` in the same directory and replace the placeholders:

```bash
cp .env.example .env
```

Some multi-app projects have more than one `.env.example`. Keep server secrets out of variables with public prefixes such as `VITE_`, `NEXT_PUBLIC_`, `PUBLIC_`, or `EXPO_PUBLIC_`. Generate strong values for secrets like `BETTER_AUTH_SECRET`, keep `.env` out of version control, and set the same keys in your hosting provider before deploying.

Common TypeScript integrations use these keys. The generated `.env.example` files remain the source of truth for your selected stack.

{/* env-contract:better-auth BETTER_AUTH_SECRET,BETTER_AUTH_URL */}
{/* env-contract:stripe VITE_STRIPE_PUBLISHABLE_KEY,STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET */}
{/* env-contract:resend RESEND_API_KEY,RESEND_FROM_EMAIL */}
{/* env-contract:sentry SENTRY_DSN,SENTRY_ENVIRONMENT,SENTRY_TRACES_SAMPLE_RATE,SENTRY_PROFILES_SAMPLE_RATE */}
{/* env-contract:upstash-redis UPSTASH_REDIS_REST_URL,UPSTASH_REDIS_REST_TOKEN,UPSTASH_REDIS_URL */}
{/* env-contract:s3 AWS_S3_REGION,AWS_S3_ACCESS_KEY_ID,AWS_S3_SECRET_ACCESS_KEY,AWS_S3_BUCKET_NAME */}
{/* env-contract:r2 R2_ACCOUNT_ID,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY,R2_BUCKET_NAME */}

| Selection     | Keys                                                                                           |
| ------------- | ---------------------------------------------------------------------------------------------- |
| Better Auth   | `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`                                                        |
| Stripe        | `VITE_STRIPE_PUBLISHABLE_KEY`, `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`                    |
| Resend        | `RESEND_API_KEY`, `RESEND_FROM_EMAIL`                                                          |
| Sentry        | `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, `SENTRY_TRACES_SAMPLE_RATE`, `SENTRY_PROFILES_SAMPLE_RATE` |
| Upstash Redis | `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN`, `UPSTASH_REDIS_URL`                      |
| Amazon S3     | `AWS_S3_REGION`, `AWS_S3_ACCESS_KEY_ID`, `AWS_S3_SECRET_ACCESS_KEY`, `AWS_S3_BUCKET_NAME`      |
| Cloudflare R2 | `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_BUCKET_NAME`                  |

## 6. Run and verify

For TypeScript projects, start the generated development scripts:

```npm
npm run dev
```

Open the web URL the command prints and confirm the starter page loads. With a separate backend, confirm its health endpoint too. Native-language entrypoints vary by framework, so the generated README is the command authority: `cargo run` for Rust, `uv run ...` for Python, `go run ...` for Go, `mix phx.server` for Phoenix, `dotnet run` for .NET, and the Expo start script for React Native.

Run the generated test or check command after the first successful startup. Do not assume one universal command across ecosystems.

## 7. Inspect what you got

Generated projects include `bts.jsonc` with the selected stack, `bts.lock.json` with the scaffold baseline, framework and config files for the ecosystem, the reproducible command that created them, and optional AI docs such as `CLAUDE.md` or `AGENTS.md`. Commit both BTS files; later commands depend on them.

## 8. Change the stack later

Inside an existing project, use `add` for new capabilities and preview first:

```npm
npm create better-fullstack@latest add -- --email resend --dry-run
```

`add` reads `bts.jsonc`, skips selections already present, and refuses to overwrite files you edited. [Project Lifecycle](/docs/getting-started/lifecycle/) explains when to use `add`, `update`, `check`, and the rest.
