How to fix useTransition() can only be used in Client Components in React
This error occurs when you try to use the useTransition() hook in a React Server Component. In Next.js 13+, all components in the app directory are Server Components by default, and hooks like useTransition require client-side execution and must be used in Client Components with the "use client" directive.
Quick fix
Fixes useTransition() can only be used in Client Components
"use client";
import { useTransition } from "react";
export default function MyComponent() {
const [isPending, startTransition] = useTransition();
// ... rest of your component
}- Add "use client" directive to the component file
- Verify the component needs client-side interactivity
- Extract useTransition logic into a dedicated Client Component
- Check for indirect hook usage through custom hooks or utilities
"use client";import { useTransition } from "react";export default function MyComponent() {const [isPending, startTransition] = useTransition();// ... rest of your component}useTransition() can only be used in Client Components
What this error means
This error indicates that you are attempting to use the useTransition() React hook in a Server Component context. React hooks like useTransition, useState, and useEffect are tightly coupled with the React rendering lifecycle and rely on client-side state management and browser runtime features. Server Components execute once per request on the server and do not have access to browser APIs, state, or lifecycle methods. In Next.js 13 and later versions using the App Router, every component is treated as a Server Component by default unless explicitly marked otherwise. The useTransition hook specifically enables non-blocking state updates and provides loading states for transitions, which are inherently client-side features. When React detects that you are trying to use this hook in a Server Component, it throws this error to prevent runtime issues. The error is part of React's architectural separation between Server and Client Components, which helps optimize performance by allowing components that don't need interactivity to run on the server, reducing the JavaScript bundle sent to the client.
Typical symptoms
- Error message appears during build or runtime stating "useTransition() can only be used in Client Components"
- Component using useTransition renders successfully in development but fails in production build
- TypeScript or ESLint warnings about using hooks in Server Components
- Application crashes when navigating to a page containing useTransition in a Server Component
- Build process fails with errors about React client hooks in Server Components
- Components with startTransition callbacks fail to execute without clear error messages
- isPending state from useTransition is undefined or causes type errors
Common causes
- Component using useTransition lacks the "use client" directive at the top of the file
- Component is located in the Next.js app directory where all components default to Server Components
- Importing and using useTransition in a file that has no client-side directive specified
- Migrating from Next.js Pages Router to App Router without adding "use client" to interactive components
- Using useTransition indirectly through a custom hook that is not marked as a Client Component
- Copying component code from older React applications that did not require explicit client declarations
- Attempting to use useTransition in a layout or page component without understanding the Server/Client Component distinction
- Mixing Server and Client Component patterns incorrectly, such as importing a hook-using component into a Server Component without proper boundaries
How to fix "useTransition() can only be used in Client Components"
Open the file containing the component that uses useTransition and add the "use client" directive as the very first line, before any imports:
"use client";
import { useTransition } from "react";
export default function MyComponent() {
const [isPending, startTransition] = useTransition();
// ... rest of your component
}The directive must be at the top of the file (before imports) and uses double quotes. This tells React and Next.js that this component and all its child components should be treated as Client Components.
Before adding "use client", confirm that your component actually requires client-side features. Ask yourself:
- Does it need to handle user interactions (clicks, form inputs)?
- Does it manage client-side state with useState or useTransition?
- Does it use browser APIs or effects?
If the answer is yes, proceed with the "use client" directive. If not, consider refactoring to use Server Actions or moving the interactive logic to a separate Client Component:
// Server Component (parent)
import ClientButton from "./ClientButton";
export default function Page() {
return (
<div>
<h1>Server-rendered content</h1>
<ClientButton /> {/* Only this is a Client Component */}
</div>
);
}If only part of your component needs useTransition, separate it into a smaller Client Component to minimize the JavaScript bundle sent to the client:
// app/components/TransitionButton.tsx (Client Component)
"use client";
import { useTransition } from "react";
export function TransitionButton({ onUpdate }: { onUpdate: () => Promise<void> }) {
const [isPending, startTransition] = useTransition();
return (
<button
onClick={() => startTransition(() => onUpdate())}
disabled={isPending}
>
{isPending ? "Updating..." : "Update"}
</button>
);
}// app/page.tsx (Server Component)
import { TransitionButton } from "./components/TransitionButton";
export default function Page() {
async function handleUpdate() {
"use server";
// Server Action logic
}
return <TransitionButton onUpdate={handleUpdate} />;
}This pattern keeps most of your component as a Server Component while isolating the interactive part.
If the error persists after adding "use client", verify that you are not importing the component into a Server Component or that custom hooks are properly marked:
// hooks/useCustomTransition.ts
"use client"; // Custom hooks also need this directive
import { useTransition } from "react";
export function useCustomTransition() {
const [isPending, startTransition] = useTransition();
// ... custom logic
return { isPending, startTransition };
}Ensure every file in the chain from your page to the hook has "use client" or is properly imported into a Client Component boundary.
If you need transition behavior outside of a component (such as in utility functions or event handlers defined outside components), use the standalone startTransition function instead:
import { startTransition } from "react";
// This can be used outside components
export function updateWithTransition(callback: () => void) {
startTransition(() => {
callback();
});
}Note that startTransition does not provide the isPending flag. Use it when you only need to mark updates as transitions without tracking loading state.
After adding the "use client" directive, clear the Next.js build cache and restart the development server to ensure changes are recognized:
rm -rf .next
npm run devFor production builds:
rm -rf .next
npm run build
npm run startNext.js caches component metadata, and stale cache can sometimes cause the error to persist even after fixing the code.
Confirm that your component is properly registered as a Client Component by checking the browser DevTools:
1. Open React DevTools in your browser
2. Locate your component in the component tree
3. Check for the component name - Client Components are rendered with their actual names, while Server Components may show as serialized data
4. Verify that useTransition returns valid [isPending, startTransition] values
You can also add a console.log to verify execution context:
"use client";
import { useTransition, useEffect } from "react";
export default function MyComponent() {
const [isPending, startTransition] = useTransition();
useEffect(() => {
console.log("Running on client:", typeof window !== "undefined");
}, []);
return <div>Client Component</div>;
}If the console.log shows true, your component is correctly running on the client.
Advanced notes
When using useTransition with Next.js Server Actions, be aware that Server Actions are asynchronous while transitions must be synchronous. However, you can wrap async Server Actions inside startTransition, and React will correctly mark state updates as transitions. In Next.js 15, there is a known issue where calling revalidatePath() from within a Server Action wrapped in startTransition() can cause the isPending flag to never reset, leaving the UI stuck in a pending state. This works correctly in Next.js 14, so consider staying on v14 if you rely heavily on this pattern.
The "use client" directive creates a boundary in your component tree. All components imported into a Client Component become part of the client bundle, even if they do not use hooks themselves. To optimize bundle size, place "use client" as deep in the component tree as possible, isolating interactive components from their server-rendered parents.
For library authors creating reusable components that use hooks, always include "use client" at the top of component files to ensure they work correctly when imported into Next.js Server Components. If you are building a component library, consider providing both Server and Client versions of components where appropriate.
The useTransition hook is particularly useful for wrapping expensive state updates that might block user input, such as filtering large lists or updating complex UI. The isPending flag can be used to show loading indicators while the transition is in progress. For simple async operations without state updates, consider using the standalone startTransition function or the experimental useOptimistic hook for optimistic UI updates.
Frequently asked questions
- What does "useTransition() can only be used in Client Components" mean?
- This error indicates that you are attempting to use the useTransition() React hook in a Server Component context. React hooks like useTransition, useState, and useEffect are tightly coupled with the React rendering lifecycle and rely on client-side state management and browser runtime features. Server Components execute once per request on the server and do not have access to browser APIs, state, or lifecycle methods.
- How do I fix "useTransition() can only be used in Client Components"?
- This error occurs when you try to use the useTransition() hook in a React Server Component. In Next.js 13+, all components in the app directory are Server Components by default, and hooks like useTransition require client-side execution and must be used in Client Components with the "use client" directive.
- What causes "useTransition() can only be used in Client Components"?
- Component using useTransition lacks the "use client" directive at the top of the file Component is located in the Next.js app directory where all components default to Server Components Importing and using useTransition in a file that has no client-side directive specified
- Is the "useTransition() can only be used in Client Components" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐React Official Documentation
- ๐React Docs: useTransition(Official Docs)
- ๐React Docs: "use client" directive(Official Docs)
- ๐Next.js Error: React client hook in Server Component(Official Docs)
- ๐Next.js Docs: Server and Client Components(Official Docs)
- ๐
- ๐