Next.js / React

A complete guide to using Invokix with a Next.js or React project. From pulling your first types to wiring up React Query hooks and validating with Zod — everything in one place.

What Invokix generates for this stack

  • TypeScript types for every schema in your contract
  • React Query v5 hooks for every endpoint
  • Zod validation schemas matching your contract exactly

Setup

1

Install dependencies

Terminal
pnpm add @tanstack/react-query zod
2

Set up QueryClientProvider

Wrap your app in a QueryClientProvider. In Next.js App Router, create a client component for this:

components/Providers.tsx
"use client"

import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { useState } from "react"

export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(() => new QueryClient())

return (
  <QueryClientProvider client={queryClient}>
    {children}
  </QueryClientProvider>
)
}
app/layout.tsx
import { Providers } from "@/components/Providers"

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
  <html>
    <body>
      <Providers>{children}</Providers>
    </body>
  </html>
)
}
3

Pull your contract outputs

Run the CLI to pull types, hooks, and schemas into your project:

Terminal
npx invokix pull

This creates three files in your src/ directory:

Generated files
src/types/orders.ts      — TypeScript types
src/hooks/useOrders.ts   — React Query v5 hooks
src/schemas/orders.ts    — Zod validation schemas
4

Use the generated hooks in your components

app/orders/page.tsx
import { useGetOrders } from "@/hooks/useOrders"

export default function OrdersPage() {
const { data: orders, isLoading } = useGetOrders()

if (isLoading) return <p>Loading...</p>

return (
  <ul>
    {orders?.map((order) => (
      <li key={order.id}>{order.status} — {order.price}</li>
    ))}
  </ul>
)
}
5

Validate API routes with Zod schemas

Use the generated schemas to validate request bodies in your API routes:

app/api/orders/route.ts
import { NextRequest, NextResponse } from "next/server"
import { CreateOrderBodySchema } from "@/schemas/orders"

export async function POST(req: NextRequest) {
const body = await req.json()

const parsed = CreateOrderBodySchema.safeParse(body)
if (!parsed.success) {
  return NextResponse.json(
    { error: "Invalid body", issues: parsed.error.issues },
    { status: 400 }
  )
}

// parsed.data is fully typed
const { price, lineItems } = parsed.data
// ... create the order
}

Keeping outputs in sync

Add the CLI to your CI pipeline so types are always up to date:

.github/workflows/ci.yml
- name: Pull latest contract outputs
run: npx invokix pull
env:
  INVOKIX_API_KEY: INVOKIX_API_KEY

- name: Type check
run: pnpm tsc --noEmit

Next steps