This tutorial adds a working `/admin` route to an existing application. You will initialize FlowPanel, expose one table or model, apply its migration, and start the admin.

> **Prefer to look around first?** The [ScrapeAI example](https://github.com/getflowpanel/flowpanel/tree/main/examples/ai-scraper) shows resources, dashboards, roles, actions, and realtime updates in one application.

## Before you start

| Requirement | Supported range | Note |
| --- | --- | --- |
| Node.js | `>=20` | Required by the CLI and runtime packages. |
| Next.js | `^16.3.0` | The CLI init and doctor commands enforce Next.js 16.3 or newer because the generated App Router wiring depends on that baseline. |
| React | `^19.0.0` | React DOM uses the same major version. |
| Drizzle ORM | `>=0.45.2 <1.0.0` | Required only when using the Drizzle adapter. |
| Prisma Client | `>=5.0.0 <7.0.0` | Required only when using the Prisma adapter. |

You need a Next.js App Router project and either Drizzle or Prisma already configured. FlowPanel ships its default admin CSS precompiled, so Tailwind is optional. Run the commands below from the project root. The Pages Router is not supported.

FlowPanel uses your existing database client and authentication. If the CLI cannot find a `getSession` helper, it creates a closed adapter: connect your provider and map `auth.role` before accessing the admin. Async role lookup is supported. An open development-only identity requires explicit `--dev-auth` and refuses production use.

## Initialize FlowPanel

```bash
pnpm dlx @flowpanel/cli init
```

The CLI detects the package manager, ORM, app directory, path alias, database client, schema, auth helper, and installed Tailwind version when present. Confirm the detected paths when prompted.

It validates local modules and named exports, then installs `@flowpanel/kit` and a version-aligned local `@flowpanel/cli`. The root layout is preserved. Conflicting files stop the operation; a busy `/admin` is replaced by the free `/flowpanel` mount, or choose `--path /ops/admin`. To inspect the plan without writing or installing anything, run:

```bash
pnpm dlx @flowpanel/cli init --dry-run
```

## Add your first resource

Open `flowpanel.config.ts`. The generated config has an empty `resources` array because FlowPanel cannot decide which application data belongs in the admin.

Use the version for your ORM and adjust the import paths and field names to match your project:


  #### Drizzle

    ```ts
import { defineAdmin, resource } from "@flowpanel/kit";
import { drizzleAdapter } from "@flowpanel/kit/drizzle";
import { getSession } from "@/server/lib/auth";
import { db } from "@/server/lib/db";
import * as schema from "@/server/lib/db/schema";

export default defineAdmin({
  adapter: drizzleAdapter({ db, schema }),
  auth: {
    session: getSession,
    role: (session) => (session as { user?: { role?: string } } | null)?.user?.role ?? "guest",
    requireRole: "admin",
  },
  resources: [
    resource(schema.users, {
      columns: ["email", "name", "role", "createdAt"],
      search: ["email", "name"],
      defaultSort: { field: "createdAt", dir: "desc" },
    }),
  ],
});
```
  
  #### Prisma

    ```ts
import { defineAdmin, resource } from "@flowpanel/kit";
import { prismaAdapter } from "@flowpanel/kit/prisma";
import { getSession } from "@/server/lib/auth";
import { prisma, type User } from "@/server/lib/prisma";

declare module "@flowpanel/kit" {
  interface FlowpanelResources {
    User: User;
  }
}

export default defineAdmin({
  adapter: prismaAdapter({ prisma, provider: "postgresql" }),
  auth: {
    session: getSession,
    role: (session) => (session as { user?: { role?: string } } | null)?.user?.role ?? "guest",
    requireRole: "admin",
  },
  resources: [
    resource("User", {
      columns: ["email", "name", "role", "createdAt"],
      search: ["email", "name"],
      defaultSort: { field: "createdAt", dir: "desc" },
    }),
  ],
});
```
  


Drizzle infers the row type from the table. A Prisma resource starts from a model name string, so the `FlowpanelResources` augmentation binds that name to the generated Prisma type. This is what makes columns, search fields, actions, and renderers type-safe.

Keep the generated auth block if it already matches your application. The example requires the `admin` role; a request without that role receives a server-side access denial, not merely a hidden navigation item.

## Apply the migration

```bash
pnpm flowpanel migrate
```

The command reads `DATABASE_URL`, applies pending SQL files in `flowpanel/migrations`, and records them in FlowPanel's migration table. Use `--dry-run` to list pending files without executing them.

The initial migration is PostgreSQL SQL. Review or adapt it before running against MySQL or SQLite. The audit table remains unused until you configure an `audit.sink`.

## Start the admin

```bash
pnpm flowpanel dev
```

Open [http://localhost:3000/admin](http://localhost:3000/admin). You should see the resource in the navigation and a paginated list at its resource URL. If the navigation is empty, confirm that `resources` contains the resource and restart the dev process so the config is reloaded.

`flowpanel dev` starts Next.js and, when `REDIS_URL` is set and the project has a `scripts/board-server.mts` (or `.ts`) file, the BullMQ board process. `init` does not create that script; see the [queues guide](/docs/guides/queues). Use your normal `pnpm dev` command if you do not need the board integration.

## What the CLI created

The exact paths follow your `app` or `src/app` layout:

| File | Purpose | You edit it when… |
| --- | --- | --- |
| `flowpanel.config.ts` | Resources, dashboards, auth, scope, realtime, and theme | You change admin behavior |
| `app/admin/[[...slug]]/page.tsx` | Catch-all admin page | You change the mount path or eject page behavior |
| `app/api/flowpanel/[...route]/route.ts` | Resource and action handlers | You change the API mount path |
| `app/api/flowpanel/stream/route.ts` | Authenticated SSE endpoint | You change the stream mount path |
| `styles/admin.css` | Thin import of FlowPanel's precompiled, isolated stylesheet | You add safe local overrides |
| `flowpanel/migrations/0001_init.sql` | FlowPanel-owned database tables | You review dialect-specific SQL |

See [Project structure](/docs/introduction/project-structure) for ownership and generated-file details.

## Choose what to build next

- Shape the list, search, filters, and access rules in [Resources](/docs/build/resources).
- Configure create and edit fields in [Forms](/docs/build/forms).
- Add operational commands in [Actions](/docs/build/actions).
- Pick the right UI layer in [Choose an extension point](/docs/customization/overview).
- Review the complete [Production readiness checklist](/docs/guides/production-readiness), then configure authentication and tenant isolation for your application.
- Read [How FlowPanel works](/docs/understand/how-flowpanel-works) before building a deeper integration.
