Skip to main content
Prerequisites: React 18+ and Tailwind CSS v4.
Built-in AI chat works out of the box through https://better-cmdk.com/api/chat as a free developer trial (no signup, 10 requests per 10 minutes).
Optional for a custom/self-hosted AI endpoint: Vercel AI SDK (ai, @ai-sdk/react).
Optional for agent actions: modifywithai.
1

Install

npm install better-cmdk
Install peer dependencies if needed:
npm install react react-dom tailwindcss
2

Import styles

In your global CSS file:
@import "tailwindcss";
@import "better-cmdk";
Optional token overrides (scoped under .bcmdk-root):
.bcmdk-root {
  --bcmdk-radius: 0.625rem;
  --bcmdk-primary: 0.205 0 0;
  --bcmdk-primary-foreground: 0.985 0 0;
  --bcmdk-border: 0.922 0 0;
}
3

Define one actions array

Start with one actions array. CommandMenu will use hosted AI chat by default.
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { CommandMenu, type CommandAction } from "better-cmdk";
import { LayoutDashboardIcon, SettingsIcon } from "lucide-react";

export function CommandPalette() {
  const [open, setOpen] = useState(false);
  const router = useRouter();

  const actions: CommandAction[] = [
    {
      name: "go-dashboard",
      label: "Go to Dashboard",
      description: "Navigate to the dashboard page",
      group: "Navigation",
      icon: <LayoutDashboardIcon className="size-4" />,
      execute: () => router.push("/dashboard"),
    },
    {
      name: "open-settings",
      label: "Open Settings",
      description: "Navigate to the settings page",
      group: "Navigation",
      icon: <SettingsIcon className="size-4" />,
      shortcut: "⌘,",
      execute: () => router.push("/settings"),
    },
    {
      name: "navigate-to",
      label: "Navigate to page",
      description: "Navigate to a specific route in the app",
      group: "Navigation",
      inputSchema: {
        path: {
          type: "string",
          description: "Destination path",
          required: true,
        },
      },
      execute: ({ path }) => router.push(String(path)),
    },
  ];

  return (
    <>
      <button onClick={() => setOpen(true)}>Open palette</button>
      <CommandMenu open={open} onOpenChange={setOpen} actions={actions} />
    </>
  );
}
Hosted chat is enabled by default via https://better-cmdk.com/api/chat so you can test quickly, but it is rate-limited (10 requests per 10 minutes) and intended for development. For production, use your own chatEndpoint or connect modifywithai for agentic workflows.
4

Optional: use your own AI endpoint

By default, better-cmdk uses the hosted trial endpoint above. Use this step to run your own route for production.Install AI SDK packages:
npm install ai @ai-sdk/react @ai-sdk/openai
Add a streaming chat endpoint (Next.js example):
// app/api/chat/route.ts
import { openai } from "@ai-sdk/openai";
import { streamText, convertToModelMessages, type UIMessage } from "ai";

export async function POST(request: Request) {
  const { messages }: { messages: UIMessage[] } = await request.json();

  const result = streamText({
    model: openai("gpt-4o-mini"),
    messages: await convertToModelMessages(messages),
    system: "You are a helpful assistant in a command palette.",
  });

  return result.toUIMessageStreamResponse();
}
Point CommandMenu to your route:
<CommandMenu
  open={open}
  onOpenChange={setOpen}
  actions={actions}
  chatEndpoint="/api/chat"
/>
5

Optional: connect modifywithai (recommended)

Install:
bun add modifywithai ai @ai-sdk/react
Create a token endpoint:
// app/api/mwai/token/route.ts
import { createAssistantTokenHandler } from "modifywithai/nextjs";

export const POST = createAssistantTokenHandler({
  appId: process.env.MWAI_APP_ID!,
});
Reuse the same actions array with useAssistant():
import { useAssistant } from "modifywithai";

const assistant = useAssistant({
  tokenEndpoint: "/api/mwai/token",
  actions,
});

<CommandMenu
  open={open}
  onOpenChange={setOpen}
  actions={actions}
  chat={assistant}
/>;
better-cmdk and modifywithai share the same CommandAction shape. Each library ignores fields it does not need.

Action behavior

Action kindConditionSelection behavior
Command-likeNo inputSchemaExecutes directly from command mode
Argument-requiringHas inputSchemaRouted through chat so the AI can provide arguments

Next steps

Extending

Design high-quality actions, approvals, custom rendering, and theming.

ModifyWithAI docs

Set up action execution, context, and escalation with the agent platform.