> ## Documentation Index
> Fetch the complete documentation index at: https://flowglad.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# @flowglad/nextjs

> Official Next.js SDK for Flowglad with App Router and Pages Router support

<Info>
  NPM Package: [@flowglad/nextjs](https://www.npmjs.com/package/@flowglad/nextjs)
</Info>

## Overview

The Next.js SDK provides a complete integration for both App Router and Pages Router, including server-side utilities and client-side components.

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @flowglad/nextjs
  ```

  ```bash yarn theme={null}
  yarn add @flowglad/nextjs
  ```

  ```bash bun theme={null}
  bun add @flowglad/nextjs
  ```
</CodeGroup>

## Requirements

* React 18 or 19
* Next.js 14 or 15

## Quick Start

### 1. Set Up Environment Variables

Add your Flowglad API key to your environment:

```bash .env theme={null}
FLOWGLAD_SECRET_KEY="sk_test_..."
```

### 2. Create Server Client

Create a Flowglad server factory function in a shared file, eg. `lib/flowglad.ts`:

<CodeGroup>
  ```ts Generic theme={null}
  import { FlowgladServer } from '@flowglad/nextjs/server'

  export const flowglad = (customerExternalId: string) => {
    // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
    return new FlowgladServer({
      customerExternalId,
      getCustomerDetails: async (customerExternalId) => {
        // Fetch customer details from YOUR database using YOUR app's ID
        const user = await db.users.findOne({ id: customerExternalId })
        if (!user) {
          throw new Error('Customer not found')
        }
        return {
          email: user.email,
          name: user.name,
        }
      },
    })
  }
  ```

  ```ts Example: Better Auth theme={null}
  import { FlowgladServer } from '@flowglad/nextjs/server'
  import { auth } from '@/utils/auth'
  import { headers } from 'next/headers'

  export const flowglad = (customerExternalId: string) => {
    return new FlowgladServer({
      customerExternalId,
      getCustomerDetails: async (customerExternalId) => {
        const session = await auth.api.getSession({
          headers: await headers(),
        })
        if (!session?.user) {
          throw new Error('User not authenticated')
        }
        return {
          email: session.user.email || '',
          name: session.user.name || ''
        }
      },
    })
  }
  ```

  ```ts Example: Supabase Auth theme={null}
  import { FlowgladServer } from '@flowglad/nextjs/server'
  import { createClient } from '@/utils/supabase/server'

  export const flowglad = (customerExternalId: string) => {
    return new FlowgladServer({
      customerExternalId,
      getCustomerDetails: async (customerExternalId) => {
        const supabase = await createClient()
        const { data: { user } } = await supabase.auth.getUser()
        if (!user) {
          throw new Error('User not authenticated')
        }
        return {
          email: user.email || '',
          name: user.user_metadata.name || user.email || ''
        }
      },
    })
  }
  ```

  ```ts Example: B2B (Organization-based) theme={null}
  import { FlowgladServer } from '@flowglad/nextjs/server'

  export const flowglad = (organizationId: string) => {
    // For B2B apps: organizationId is ID from YOUR app's database
    return new FlowgladServer({
      customerExternalId: organizationId,
      getCustomerDetails: async (customerExternalId) => {
        // Fetch organization details from YOUR database using YOUR org ID
        const org = await db.organizations.findOne({ id: customerExternalId })
        if (!org) {
          throw new Error('Organization not found')
        }
        return {
          email: org.billingEmail || org.ownerEmail,
          name: org.name,
        }
      },
    })
  }
  ```
</CodeGroup>

<Note>
  **Important:** `customerExternalId` is the ID from **your app's database** (e.g., `user.id` or `organization.id`), **not** Flowglad's customer ID.

  **B2C apps:** Pass `user.id` as `customerExternalId`\
  **B2B apps:** Pass `organization.id` or `team.id` as `customerExternalId`
</Note>

<Info>
  Flowglad integrates seamlessly with your auth provider. Read more about auth options [here](/sdks/auth).
</Info>

### 3. Create API Route Handler

Create a route handler to handle Flowglad API requests from your frontend. The Server SDK provides route handler constructors that enable your client to communicate with your server, allowing you to load billing and feature access data via the [`useBilling` hook](/sdks/react#usebilling-hook) on your frontend. It should handle requests at `/api/flowglad/...`

<Tabs>
  <Tab title="Next.js App Router">
    ```ts title="app/api/flowglad/[...path]/route.ts" theme={null}
    import { nextRouteHandler } from '@flowglad/nextjs/server'
    import { flowglad } from '@/lib/flowglad'
    import { customerIdFromRequest } from '@/lib/auth'

    export const { GET, POST } = nextRouteHandler({
      flowglad,
      getCustomerExternalId: async (req) => {
        const externalId = await customerIdFromRequest(req)
        if (!externalId) {
          throw new Error('Unable to determine customer external ID')
        }
        return externalId
      },
    })
    ```
  </Tab>

  <Tab title="Next.js Pages Router">
    ```ts title="pages/api/flowglad/[...path].ts" theme={null}
    import { pagesRouteHandler } from '@flowglad/nextjs/server'
    import { flowglad } from '@/lib/flowglad'
    import { customerIdFromRequest } from '@/lib/auth'

    export default pagesRouteHandler({
      flowglad,
      getCustomerExternalId: async (req) => {
        const externalId = await customerIdFromRequest(req)
        if (!externalId) {
          throw new Error('Unable to determine customer external ID')
        }
        return externalId
      },
    })
    ```
  </Tab>

  <Tab title="Express">
    ```ts title="server.ts" theme={null}
    import express from 'express'
    import { expressRouter } from '@flowglad/server/express'
    import { flowglad } from './lib/flowglad'
    import { customerIdFromRequest } from './lib/auth'

    const app = express()

    app.use(
      '/api/flowglad',
      expressRouter({
        flowglad,
        getCustomerExternalId: async (req) => {
          const externalId = await customerIdFromRequest(req)
          if (!externalId) {
            throw new Error('Unable to determine customer external ID')
          }
          return externalId
        },
      })
    )
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```ts title="server.ts" theme={null}
    import { requestHandler } from '@flowglad/server'
    import { flowglad } from './lib/flowglad'
    import { customerIdFromRequest } from './lib/auth'
    import type { HTTPMethod } from '@flowglad/shared'

    const flowgladHandler = requestHandler({
      flowglad,
      getCustomerExternalId: async (req) => {
        const externalId = await customerIdFromRequest(req)
        if (!externalId) {
          throw new Error('Unable to determine customer external ID')
        }
        return externalId
      },
    })

    // Example: Hono, Cloudflare Workers, Elysia, etc.
    // Adapt this pattern to your framework
    async function handleFlowgladRequest(request: Request): Promise<Response> {
      const url = new URL(request.url)
      const path = url.pathname
        .replace('/api/flowglad/', '')
        .split('/')
        .filter((segment) => segment !== '')

      const result = await flowgladHandler(
        {
          path,
          method: request.method as HTTPMethod,
          query:
            request.method === 'GET'
              ? Object.fromEntries(url.searchParams)
              : undefined,
          body:
            request.method !== 'GET'
              ? await request.json().catch(() => ({}))
              : undefined,
        },
        request
      )

      return Response.json(
        {
          error: result.error,
          data: result.data,
        },
        {
          status: result.status,
        }
      )
    }
    ```
  </Tab>
</Tabs>

### 4. Wrap Your App with FlowgladProvider

<Tabs>
  <Tab title="Next.js App Router">
    ```tsx title="app/layout.tsx" theme={null}
    import { FlowgladProvider } from '@flowglad/nextjs'

    export default function RootLayout({ children }) {
      return (
        <html>
          <body>
            <FlowgladProvider>
              {children}
            </FlowgladProvider>
          </body>
        </html>
      )
    }
    ```
  </Tab>

  <Tab title="Next.js Pages Router">
    ```tsx title="pages/_app.tsx" theme={null}
    import { FlowgladProvider } from '@flowglad/nextjs'

    export default function App({ Component, pageProps }) {
      return (
        <FlowgladProvider>
          <Component {...pageProps} />
        </FlowgladProvider>
      )
    }
    ```
  </Tab>

  <Tab title="Vite + React">
    ```tsx title="src/App.tsx" theme={null}
    import { FlowgladProvider } from '@flowglad/react'

    export default function App({ children }) {
      return (
        <FlowgladProvider>
          {children}
        </FlowgladProvider>
      )
    }
    ```
  </Tab>
</Tabs>

### 5. Use the Billing Hook

<Tabs>
  <Tab title="Next.js">
    ```tsx theme={null}
    "use client"

    import { useBilling } from '@flowglad/nextjs'

    export default function BillingPage() {
      const { checkFeatureAccess, createCheckoutSession } = useBilling()

      if (!checkFeatureAccess) {
        return <div>Loading...</div>
      }

      if (checkFeatureAccess('premium_feature')) {
        return <div>You have access to premium features!</div>
      }

      return (
        <button
          onClick={() =>
            createCheckoutSession({
              priceSlug: 'pro_plan',
              successUrl: window.location.href,
              cancelUrl: window.location.href,
              autoRedirect: true,
            })
          }
        >
          Upgrade to Premium
        </button>
      )
    }
    ```
  </Tab>

  <Tab title="Vite + React">
    ```tsx theme={null}
    import { useBilling } from '@flowglad/react'

    export default function BillingPage() {
      const { checkFeatureAccess, createCheckoutSession } = useBilling()

      if (!checkFeatureAccess) {
        return <div>Loading...</div>
      }

      if (checkFeatureAccess('premium_feature')) {
        return <div>You have access to premium features!</div>
      }

      return (
        <button
          onClick={() =>
            createCheckoutSession({
              priceSlug: 'pro_plan',
              successUrl: window.location.href,
              cancelUrl: window.location.href,
              autoRedirect: true,
            })
          }
        >
          Upgrade to Premium
        </button>
      )
    }
    ```
  </Tab>
</Tabs>

## Key Features

* **App Router Support**: First-class support for Next.js App Router with Server Components
* **Pages Router Support**: Full compatibility with Pages Router
* **Type-safe Route Handlers**: Automatic type inference for API routes
* **Server-side Utilities**: Access billing data in Server Components and API routes
* **Client Components**: Pre-built components for subscriptions and billing
* **React Context**: Global billing state management

## API Reference

### Server Exports

Import from `@flowglad/nextjs/server`:

#### `FlowgladServer`

The main server class for backend operations. See the [Server SDK documentation](/sdks/server) for full details.

#### Route Handler

Creates GET and POST handlers for App Router:

```ts theme={null}
import { nextRouteHandler} from '@flowglad/nextjs/server'
import { flowglad } from '@/utils/flowglad'

export const { GET, POST } = nextRouteHandler({
  flowglad,
  // derive customer external id from the request
  getCustomerExternalId: async (req) => {
    // for B2B apps, provide organization or team id instead
    const user = await getUserForReq(req)
    return user.id
  },
  // optional hooks for custom behavior
  beforeRequest: async () => {
    // side effect to run before the request is processed
  },
  afterRequest: async () => {
    // side effect to run after the request is processed
  },
  onError: (error) => {
    // handle errors
  }
})
```

### Client Exports

You can import the following from `@flowglad/nextjs`:

#### `FlowgladProvider`

The main provider component. See the [React SDK documentation](/sdks/react) for full details on props and usage.

#### `useBilling()`

Access billing data and functions. See the [React SDK documentation](/sdks/react) for full API reference.

## Server Setup

```ts lib/flowglad.ts theme={null}
import { FlowgladServer } from '@flowglad/nextjs/server'

export const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      // Fetch customer details from YOUR database using YOUR app's ID
      const user = await db.users.findOne({ id: externalId })
      if (!user) {
        throw new Error('Customer not found')
      }
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}
```

```ts app/api/flowglad/[...path]/route.ts theme={null}
import { nextRouteHandler } from '@flowglad/nextjs/server'
import { flowglad } from '@/utils/flowglad'

export const { GET, POST } = nextRouteHandler({
  flowglad,
  getCustomerExternalId: async (req) => {
    // Extract customerExternalId from your auth/session
    // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
    // For B2C: return user.id (from your database)
    // For B2B: return organization.id (from your database)
    const userId = await getUserIdFromRequest(req)
    if (!userId) {
      throw new Error('User not authenticated')
    }
    return userId
  },
})
```

<Note>
  **Important:** `customerExternalId` is the ID from **your app's database** (e.g., `user.id` or `organization.id`), **not** Flowglad's customer ID.

  **B2C apps:** Pass `user.id` as `customerExternalId`\
  **B2B apps:** Pass `organization.id` or `team.id` as `customerExternalId`

  Flowglad doesn't need to know how you authenticate—just provide the ID from your system that represents the customer entity which will be billed.
</Note>

## Complete Example

For full working examples, check out our [example projects](https://github.com/flowglad/examples) with authentication and billing integration.

## Next Steps

<CardGroup cols={2}>
  <Card title="React SDK" icon="react" href="/sdks/react">
    Learn about React components and hooks
  </Card>

  <Card title="Server SDK" icon="server" href="/sdks/server">
    Explore server-side capabilities
  </Card>
</CardGroup>
