# Framework guides

What `npx create-bucker` does for each framework it recognizes, and what to do by hand where it can't. This page is **generated from the wizard's own plans** (`tooling/create-bucker/src/snippets.ts`), so it lists exactly the files the wizard writes. Nothing here is a promise the wizard does not keep.

Python is wired by one top-of-file line and the middleware step printed after it; [the Python SDK](sdk-python.md) has the rest (Starlette, Celery). **Already on Sentry?** When the wizard finds `@sentry/*` or `sentry-sdk`, it does not add a second SDK: it points your `SENTRY_DSN` at the project's Sentry-SDK DSN, as a diff you confirm (`--ignore-sentry` to install the Bucker SDK instead); see [switch from Sentry](switch-from-sentry.md). For any other language, point an unmodified Sentry SDK at your DSN the same way. `npx create-bucker --uninstall` removes everything the wizard wrote.

```bash
npx create-bucker --dsn "https://<publicKey>@us.ingest.bucker.io/<projectId>"
```

Add `--dry-run` to print the plan below for your own project without writing anything, and `--framework <name>` to override detection. If you installed the SDK by hand, [getting started](getting-started.md) has the same steps without the wizard.

## Next.js (App Router)

Detected from a `next` dependency or a `next.config.*`. There is no separate Next.js SDK: the wizard wires both halves, `@bucker/node` on the server and `@bucker/browser` in the browser. With `--source-maps` it also wraps `next.config` in `withBucker` (`@bucker/bundler-plugin/next`), which stamps Debug IDs after Turbopack or webpack finishes and fails the build when a map does not resolve.

**Installs:** `@bucker/browser`, `@bucker/node`

| File | Purpose |
| --- | --- |
| `instrumentation.ts` | server-side init + onRequestError capture |
| `instrumentation-client.ts` | browser init (Next.js >= 15.3) |
| `app/bucker-verify/page.tsx` | verify page that throws in the browser |
| `app/api/bucker-verify/route.ts` | verify route that throws on the server |

**Environment** (written to `.env.local`, never into source):

- `BUCKER_DSN`: Server-side DSN. Never exposed to the browser bundle.
- `NEXT_PUBLIC_BUCKER_DSN`: Browser DSN. Public by design — it authenticates ingest, nothing else.

**Entry file:** nothing is injected into your code.

**Verify:** Start the dev server and open /bucker-verify, then /api/bucker-verify.

**By hand afterwards:**

- On Next.js < 15.3 there is no instrumentation-client hook: import the generated instrumentation-client file once from your root layout.
- On Next.js < 15 add `experimental: { instrumentationHook: true }` to next.config.
- Set BUCKER_RELEASE (server) and NEXT_PUBLIC_BUCKER_RELEASE (browser) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Next.js (Pages Router)

The same two SDKs, with the verify files in `pages/` instead of `app/`.

**Installs:** `@bucker/browser`, `@bucker/node`

| File | Purpose |
| --- | --- |
| `instrumentation.ts` | server-side init + onRequestError capture |
| `instrumentation-client.ts` | browser init (Next.js >= 15.3) |
| `pages/bucker-verify.tsx` | verify page that throws in the browser |
| `pages/api/bucker-verify.ts` | verify route that throws on the server |

**Environment** (written to `.env.local`, never into source):

- `BUCKER_DSN`: Server-side DSN. Never exposed to the browser bundle.
- `NEXT_PUBLIC_BUCKER_DSN`: Browser DSN. Public by design — it authenticates ingest, nothing else.

**Entry file:** nothing is injected into your code.

**Verify:** Start the dev server and open /bucker-verify, then /api/bucker-verify.

**By hand afterwards:**

- On Next.js < 15.3 there is no instrumentation-client hook: import the generated instrumentation-client file once from your root layout.
- On Next.js < 15 add `experimental: { instrumentationHook: true }` to next.config.
- Set BUCKER_RELEASE (server) and NEXT_PUBLIC_BUCKER_RELEASE (browser) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Express

A Node server with an `express` dependency.

**Installs:** `@bucker/node`

| File | Purpose |
| --- | --- |
| `src/bucker.server.ts` | SDK init + crash handlers |
| `src/bucker-verify.ts` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`src/index.ts` in this example): `import './bucker.server.js'`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run the generated src/bucker-verify.ts script.

**By hand afterwards:**

- For per-request context, add `app.use(requestHandler(bucker))` before your routes and `app.use(errorHandler(bucker))` after them — both are exported from `@bucker/node`.
- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Fastify

A Node server with a `fastify` dependency.

**Installs:** `@bucker/node`

| File | Purpose |
| --- | --- |
| `src/bucker.server.ts` | SDK init + crash handlers |
| `src/bucker-verify.ts` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`src/index.ts` in this example): `import './bucker.server.js'`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run the generated src/bucker-verify.ts script.

**By hand afterwards:**

- For per-request context, register the hooks: `const hooks = fastifyHooks(bucker); app.addHook("onRequest", hooks.onRequest); app.addHook("onError", hooks.onError)`.
- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Plain Node

Any other Node process: a worker, a CLI, a queue consumer.

**Installs:** `@bucker/node`

| File | Purpose |
| --- | --- |
| `src/bucker.server.ts` | SDK init + crash handlers |
| `src/bucker-verify.ts` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`src/index.ts` in this example): `import './bucker.server.js'`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run the generated src/bucker-verify.ts script.

**By hand afterwards:**

- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## SvelteKit

Detected from `@sveltejs/kit`. Both hooks files are written when you have none; an existing one is left alone and the lines to add are printed.

**Installs:** `@bucker/browser`, `@bucker/node`

| File | Purpose |
| --- | --- |
| `src/hooks.server.ts` | server init + handle/handleError |
| `src/hooks.client.ts` | browser init + handleError |
| `src/routes/bucker-verify/+page.server.ts` | verify route that throws on the server |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Server DSN ($env/dynamic/private).
- `PUBLIC_BUCKER_DSN`: Browser DSN ($env/dynamic/public). Public by design.

**Entry file:** nothing is injected into your code.

**Verify:** Start the dev server and open /bucker-verify.

**By hand afterwards:**

- Set BUCKER_RELEASE (server) and PUBLIC_BUCKER_RELEASE (browser) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Nuxt

Detected from `nuxt`. Two plugins, registered by Nuxt from their directories; no file of yours is edited.

**Installs:** `@bucker/browser`, `@bucker/node`

| File | Purpose |
| --- | --- |
| `plugins/bucker.client.ts` | browser init (Nuxt plugin) |
| `server/plugins/bucker.ts` | server init (Nitro plugin) |
| `server/api/bucker-verify.ts` | verify route that throws on the server |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Server DSN (Nitro).
- `NUXT_PUBLIC_BUCKER_DSN`: Browser DSN, read as runtimeConfig.public.buckerDsn. Public by design.

**Entry file:** nothing is injected into your code.

**Verify:** Start the dev server and request /api/bucker-verify.

**By hand afterwards:**

- Declare the browser DSN in nuxt.config so Nuxt maps NUXT_PUBLIC_BUCKER_DSN onto it: `runtimeConfig: { public: { buckerDsn: "", buckerRelease: "" } }`.
- Set BUCKER_RELEASE (server) and NUXT_PUBLIC_BUCKER_RELEASE (browser) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Remix and React Router

Detected from `@remix-run/*` or `@react-router/dev`. `handleError` is re-exported from your `app/entry.server`.

**Installs:** `@bucker/browser`, `@bucker/node`

| File | Purpose |
| --- | --- |
| `app/bucker.server.ts` | server init + handleError |
| `app/bucker.client.ts` | browser init |
| `app/routes/bucker-verify.tsx` | verify route whose loader throws |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Server DSN.
- `VITE_BUCKER_DSN`: Browser DSN. Public by design.

**Entry file:** one line is injected at the top of your entry file (`app/entry.server.tsx` in this example): `export { handleError } from './bucker.server'`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Start the dev server and open /bucker-verify.

**By hand afterwards:**

- Import the browser init once from app/entry.client: `import './bucker.client'`. In your root ErrorBoundary, call `captureRouteError(useRouteError())` from '@bucker/browser/react'.
- Set BUCKER_RELEASE (server) and VITE_BUCKER_RELEASE (browser) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Django

Detected from `django` in a Python manifest or a `manage.py`. One line goes at the top of the settings module `manage.py` names.

**Installs:** `bucker-sdk` from PyPI, which you install into your environment (`pip install bucker-sdk`)

| File | Purpose |
| --- | --- |
| `bucker_verify.py` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`shop/settings.py` in this example): `import bucker_sdk; bucker_sdk.init()`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run `python bucker_verify.py` with BUCKER_DSN exported.

**By hand afterwards:**

- Install the SDK into the environment that runs the app: `pip install bucker-sdk` (or `uv add bucker-sdk` / `poetry add bucker-sdk`).
- Python does not read .env by itself: export BUCKER_DSN in the process environment (or load .env with python-dotenv, which `flask run` does when it is installed).
- Capture request errors with the WSGI or ASGI middleware: in wsgi.py `application = BuckerWsgiMiddleware(get_wsgi_application())` (from bucker_sdk.wsgi), or in asgi.py `application = BuckerAsgiMiddleware(get_asgi_application())` (from bucker_sdk.asgi).
- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Flask

Detected from `flask` in a Python manifest. One line goes at the top of the module that builds the app.

**Installs:** `bucker-sdk` from PyPI, which you install into your environment (`pip install bucker-sdk`)

| File | Purpose |
| --- | --- |
| `bucker_verify.py` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`app/__init__.py` in this example): `import bucker_sdk; bucker_sdk.init()`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run `python bucker_verify.py` with BUCKER_DSN exported.

**By hand afterwards:**

- Install the SDK into the environment that runs the app: `pip install bucker-sdk` (or `uv add bucker-sdk` / `poetry add bucker-sdk`).
- Python does not read .env by itself: export BUCKER_DSN in the process environment (or load .env with python-dotenv, which `flask run` does when it is installed).
- Capture request errors: `app.wsgi_app = BuckerWsgiMiddleware(app.wsgi_app)` (from bucker_sdk.wsgi) right after the app is created.
- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## FastAPI

Detected from `fastapi` in a Python manifest. One line goes at the top of the module that builds the app, so it runs before the lifespan does.

**Installs:** `bucker-sdk` from PyPI, which you install into your environment (`pip install bucker-sdk`)

| File | Purpose |
| --- | --- |
| `bucker_verify.py` | standalone script that sends one deliberate error |

**Environment** (written to `.env`, never into source):

- `BUCKER_DSN`: Bucker project DSN.

**Entry file:** one line is injected at the top of your entry file (`main.py` in this example): `import bucker_sdk; bucker_sdk.init()`. It must be the first import, so crash handlers are installed before anything else evaluates.

**Verify:** Run `python bucker_verify.py` with BUCKER_DSN exported.

**By hand afterwards:**

- Install the SDK into the environment that runs the app: `pip install bucker-sdk` (or `uv add bucker-sdk` / `poetry add bucker-sdk`).
- Python does not read .env by itself: export BUCKER_DSN in the process environment (or load .env with python-dotenv, which `flask run` does when it is installed).
- Capture request errors: `app.add_middleware(BuckerAsgiMiddleware)` (from bucker_sdk.asgi) right after the app is created.
- Set BUCKER_RELEASE to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## Browser app

Vite, a root `index.html`, or a UI framework dependency (React, Vue, Svelte) with no server half.

**Installs:** `@bucker/browser`

| File | Purpose |
| --- | --- |
| `bucker.client.ts` | browser SDK init |
| `bucker-verify.html` | verify page that throws in the browser |

**Environment** (written to `.env`, never into source):

- `VITE_BUCKER_DSN`: Browser DSN. Public by design; rename the prefix for your bundler.

**Entry file:** nothing is injected into your code.

**Verify:** Open /bucker-verify.html through your dev server.

**By hand afterwards:**

- Import the generated bucker.client file once, as early as possible in your app entry.
- Without a bundler, bare specifiers like `@bucker/browser` do not resolve in the browser — serve through Vite or add an import map.
- Set VITE_BUCKER_RELEASE (or your bundler's public equivalent) to your build's version or git SHA wherever the app is built or deployed; release health and regressions are per release, and without a release the SDK sends no sessions.

## When the wizard does not know your framework

Use the closest of the 12 sections above, or install the SDK by hand: `@bucker/node` for any server, `@bucker/browser` for any page. The init call is the same everywhere, and [if nothing arrives](troubleshooting.md) names the checks in the order they find the problem.
