diff --git a/docs/02-app/01-building-your-application/06-configuring/02-eslint.mdx b/docs/02-app/01-building-your-application/06-configuring/02-eslint.mdx
index 55e3f9655ab0..f32817faf8bb 100644
--- a/docs/02-app/01-building-your-application/06-configuring/02-eslint.mdx
+++ b/docs/02-app/01-building-your-application/06-configuring/02-eslint.mdx
@@ -88,6 +88,7 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/
| | [@next/next/inline-script-id](/docs/messages/inline-script-id) | Enforce `id` attribute on `next/script` components with inline content. |
| | [@next/next/next-script-for-ga](/docs/messages/next-script-for-ga) | Prefer `next/script` component when using the inline script for Google Analytics. |
| | [@next/next/no-assign-module-variable](/docs/messages/no-assign-module-variable) | Prevent assignment to the `module` variable. |
+| | [@next/next/no-async-client-component](/docs/messages/no-async-client-component) | Prevent client components from being async functions. |
| | [@next/next/no-before-interactive-script-outside-document](/docs/messages/no-before-interactive-script-outside-document) | Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`. |
| | [@next/next/no-css-tags](/docs/messages/no-css-tags) | Prevent manual stylesheet tags. |
| | [@next/next/no-document-import-in-page](/docs/messages/no-document-import-in-page) | Prevent importing `next/document` outside of `pages/_document.js`. |
diff --git a/errors/no-async-client-component.md b/errors/no-async-client-component.md
new file mode 100644
index 000000000000..c2fb5e712c97
--- /dev/null
+++ b/errors/no-async-client-component.md
@@ -0,0 +1,12 @@
+# No async client component
+
+> Client components cannot be async functions.
+
+#### Why This Error Occurred
+
+As per the [React Server Component RFC on promise support](https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md), [client components cannot be async functions](https://github.com/acdlite/rfcs/blob/first-class-promises/text/0000-first-class-support-for-promises.md#why-cant-client-components-be-async-functions).
+
+#### Possible Ways to Fix It
+
+1. Remove the `async` keyword from the client component function declaration, or
+2. Convert the client component to a server component
diff --git a/packages/eslint-plugin-next/src/index.ts b/packages/eslint-plugin-next/src/index.ts
index c0d365b0cd9f..78b8553f8f43 100644
--- a/packages/eslint-plugin-next/src/index.ts
+++ b/packages/eslint-plugin-next/src/index.ts
@@ -5,6 +5,7 @@ module.exports = {
'inline-script-id': require('./rules/inline-script-id'),
'next-script-for-ga': require('./rules/next-script-for-ga'),
'no-assign-module-variable': require('./rules/no-assign-module-variable'),
+ 'no-async-client-component': require('./rules/no-async-client-component'),
'no-before-interactive-script-outside-document': require('./rules/no-before-interactive-script-outside-document'),
'no-css-tags': require('./rules/no-css-tags'),
'no-document-import-in-page': require('./rules/no-document-import-in-page'),
@@ -29,6 +30,7 @@ module.exports = {
'@next/next/google-font-display': 'warn',
'@next/next/google-font-preconnect': 'warn',
'@next/next/next-script-for-ga': 'warn',
+ '@next/next/no-async-client-component': 'warn',
'@next/next/no-before-interactive-script-outside-document': 'warn',
'@next/next/no-css-tags': 'warn',
'@next/next/no-head-element': 'warn',
diff --git a/packages/eslint-plugin-next/src/rules/no-async-client-component.ts b/packages/eslint-plugin-next/src/rules/no-async-client-component.ts
new file mode 100644
index 000000000000..387b7973b3d8
--- /dev/null
+++ b/packages/eslint-plugin-next/src/rules/no-async-client-component.ts
@@ -0,0 +1,76 @@
+import { defineRule } from '../utils/define-rule'
+
+const url = 'https://nextjs.org/docs/messages/no-async-client-component'
+const description = 'Prevent client components from being async functions.'
+const message = `${description} See: ${url}`
+
+function isCapitalized(str: string): boolean {
+ return /[A-Z]/.test(str?.[0])
+}
+
+export = defineRule({
+ meta: {
+ docs: {
+ description,
+ recommended: true,
+ url,
+ },
+ type: 'problem',
+ schema: [],
+ },
+
+ create(context) {
+ return {
+ Program(node) {
+ let isClientComponent: boolean = false
+
+ for (const block of node.body) {
+ if (
+ block.type === 'ExpressionStatement' &&
+ block.expression.type === 'Literal' &&
+ block.expression.value === 'use client'
+ ) {
+ isClientComponent = true
+ }
+
+ if (block.type === 'ExportDefaultDeclaration' && isClientComponent) {
+ // export default async function MyComponent() {...}
+ if (
+ block.declaration.type === 'FunctionDeclaration' &&
+ block.declaration.async &&
+ isCapitalized(block.declaration.id.name)
+ ) {
+ context.report({
+ node: block,
+ message,
+ })
+ }
+
+ // async function MyComponent() {...}; export default MyComponent;
+ if (
+ block.declaration.type === 'Identifier' &&
+ isCapitalized(block.declaration.name)
+ ) {
+ const functionName = block.declaration.name
+ const functionDeclaration = node.body.find(
+ (localBlock) =>
+ localBlock.type === 'FunctionDeclaration' &&
+ localBlock.id.name === functionName
+ )
+
+ if (
+ functionDeclaration.type === 'FunctionDeclaration' &&
+ functionDeclaration.async
+ ) {
+ context.report({
+ node: functionDeclaration,
+ message,
+ })
+ }
+ }
+ }
+ }
+ },
+ }
+ },
+})
diff --git a/test/unit/eslint-plugin-next/no-async-client-component.test.ts b/test/unit/eslint-plugin-next/no-async-client-component.test.ts
new file mode 100644
index 000000000000..f4d43cd2077e
--- /dev/null
+++ b/test/unit/eslint-plugin-next/no-async-client-component.test.ts
@@ -0,0 +1,132 @@
+import rule from '@next/eslint-plugin-next/dist/rules/no-async-client-component'
+import { RuleTester } from 'eslint'
+;(RuleTester as any).setDefaultConfig({
+ parserOptions: {
+ ecmaVersion: 2018,
+ sourceType: 'module',
+ ecmaFeatures: {
+ modules: true,
+ jsx: true,
+ },
+ },
+})
+const ruleTester = new RuleTester()
+
+const message =
+ 'Prevent client components from being async functions. See: https://nextjs.org/docs/messages/no-async-client-component'
+
+ruleTester.run('no-async-client-component single line', rule, {
+ valid: [
+ `
+ export default async function MyComponent() {
+ return <>>
+ }
+ `,
+ ],
+ invalid: [
+ {
+ code: `
+ "use client"
+
+ export default async function MyComponent() {
+ return <>>
+ }
+ `,
+ errors: [
+ {
+ message,
+ },
+ ],
+ },
+ ],
+})
+
+ruleTester.run('no-async-client-component single line capitalization', rule, {
+ valid: [
+ `
+ "use client"
+
+ export default async function myFunction() {
+ return ''
+ }
+ `,
+ ],
+ invalid: [
+ {
+ code: `
+ "use client"
+
+ export default async function MyFunction() {
+ return ''
+ }
+ `,
+ errors: [
+ {
+ message,
+ },
+ ],
+ },
+ ],
+})
+
+ruleTester.run('no-async-client-component multiple line', rule, {
+ valid: [
+ `
+ async function MyComponent() {
+ return <>>
+ }
+
+ export default MyComponent
+ `,
+ ],
+ invalid: [
+ {
+ code: `
+ "use client"
+
+ async function MyComponent() {
+ return <>>
+ }
+
+ export default MyComponent
+ `,
+ errors: [
+ {
+ message,
+ },
+ ],
+ },
+ ],
+})
+
+ruleTester.run('no-async-client-component multiple line capitalization', rule, {
+ valid: [
+ `
+ "use client"
+
+ async function myFunction() {
+ return ''
+ }
+
+ export default myFunction
+ `,
+ ],
+ invalid: [
+ {
+ code: `
+ "use client"
+
+ async function MyFunction() {
+ return ''
+ }
+
+ export default MyFunction
+ `,
+ errors: [
+ {
+ message,
+ },
+ ],
+ },
+ ],
+})