Repository: vercel/next.js
Pull request: Turbopack: Better error for sassOptions.functions as it's unsupported

## What?

Implements an error for the case where Turbopack is used with sassOptions.functions. 

Fixes #65241

Closes PACK-5715

Changed files:
filename: docs/01-app/03-api-reference/05-config/01-next-config-js/sassOptions.mdx
patch: @@ -43,4 +43,7 @@ const nextConfig = {
 module.exports = nextConfig
 ```
 
-> **Good to know:** `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties.
+> **Good to know:**
+>
+> - `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties.
+> - The `functions` property for defining custom Sass functions is only supported with webpack. When using Turbopack, custom Sass functions are not available because Turbopack's Rust-based architecture cannot directly execute JavaScript functions passed through this option.

filename: docs/01-app/03-api-reference/08-turbopack.mdx
patch: @@ -72,16 +72,16 @@ Turbopack in Next.js has **zero-configuration** for the common use cases. Below
 
 ### CSS and styling
 
-| Feature            | Status                  | Notes                                                                                                                                                                                                           |
-| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **Global CSS**     | **Supported**           | Import `.css` files directly in your application.                                                                                                                                                               |
-| **CSS Modules**    | **Supported**           | `.module.css` files work natively (Lightning CSS).                                                                                                                                                              |
-| **CSS Nesting**    | **Supported**           | Lightning CSS supports [modern CSS nesting](https://lightningcss.dev/).                                                                                                                                         |
-| **@import syntax** | **Supported**           | Combine multiple CSS files.                                                                                                                                                                                     |
-| **PostCSS**        | **Supported**           | Automatically processes `postcss.config.js` in a Node.js worker pool. Useful for Tailwind, Autoprefixer, etc.                                                                                                   |
-| **Sass / SCSS**    | **Supported** (Next.js) | For Next.js, Sass is supported out of the box. In the future, Turbopack standalone usage will likely require a loader config.                                                                                   |
-| **Less**           | Planned via plugins     | Not yet supported by default. Will likely require a loader config once custom loaders are stable.                                                                                                               |
-| **Lightning CSS**  | **In Use**              | Handles CSS transformations. Some low-usage CSS Modules features (like `:local/:global` as standalone pseudo-classes) are not yet supported. [See below for more details.](#unsupported-and-unplanned-features) |
+| Feature            | Status                  | Notes                                                                                                                                                                                                                                                                                                                                                                 |
+| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Global CSS**     | **Supported**           | Import `.css` files directly in your application.                                                                                                                                                                                                                                                                                                                     |
+| **CSS Modules**    | **Supported**           | `.module.css` files work natively (Lightning CSS).                                                                                                                                                                                                                                                                                                                    |
+| **CSS Nesting**    | **Supported**           | Lightning CSS supports [modern CSS nesting](https://lightningcss.dev/).                                                                                                                                                                                                                                                                                               |
+| **@import syntax** | **Supported**           | Combine multiple CSS files.                                                                                                                                                                                                                                                                                                                                           |
+| **PostCSS**        | **Supported**           | Automatically processes `postcss.config.js` in a Node.js worker pool. Useful for Tailwind, Autoprefixer, etc.                                                                                                                                                                                                                                                         |
+| **Sass / SCSS**    | **Supported** (Next.js) | For Next.js, Sass is supported out of the box. Custom Sass functions (`sassOptions.functions`) are not supported because Turbopack's Rust-based architecture cannot directly execute JavaScript functions, unlike webpack's Node.js environment. Use webpack if you need this feature. In the future, Turbopack standalone usage will likely require a loader config. |
+| **Less**           | Planned via plugins     | Not yet supported by default. Will likely require a loader config once custom loaders are stable.                                                                                                                                                                                                                                                                     |
+| **Lightning CSS**  | **In Use**              | Handles CSS transformations. Some low-usage CSS Modules features (like `:local/:global` as standalone pseudo-classes) are not yet supported. [See below for more details.](#unsupported-and-unplanned-features)                                                                                                                                                       |
 
 ### Assets
 
@@ -175,6 +175,8 @@ Some features are not yet implemented or not planned:
   - `:import` and `:export` ICSS rules.
   - `composes` in `.module.css` composing a `.css` file. In webpack this would treat the `.css` file as a CSS Module, with Turbopack the `.css` file will always be global. This means that if you want to use `composes` in a CSS Module, you need to change the `.css` file to a `.module.css` file.
   - `@import` in CSS Modules importing `.css` as a CSS Module. In webpack this would treat the `.css` file as a CSS Module, with Turbopack the `.css` file will always be global. This means that if you want to use `@import` in a CSS Module, you need to change the `.css` file to a `.module.css` file.
+- **`sassOptions.functions`**
+  Custom Sass functions defined in `sassOptions.functions` are not supported. This feature allows defining JavaScript functions that can be called from Sass code during compilation. Turbopack's Rust-based architecture cannot directly execute JavaScript functions passed through `sassOptions.functions`, unlike webpack's Node.js-based sass-loader which runs entirely in JavaScript. If you're using custom Sass functions, you'll need to use webpack instead of Turbopack.
 - **`webpack()` configuration** in `next.config.js`
   Turbopack replaces webpack, so `webpack()` configs are not recognized. Use the [`turbopack` config](/docs/app/api-reference/config/next-config-js/turbopack) instead.
 - **Yarn PnP**

filename: packages/next/errors.json
patch: @@ -890,5 +890,6 @@
   "889": "Unknown \\`cacheLife()\\` profile \"%s\" is not configured in next.config.js\\nmodule.exports = {\n  cacheLife: {\n      \"%s\": ...\\n    }\n}",
   "890": "Received an underlying cookies object that does not match either `cookies` or `mutableCookies`",
   "891": "Failed to read build paths file \"%s\": %s",
-  "892": "Failed to resolve glob pattern \"%s\": %s"
+  "892": "Failed to resolve glob pattern \"%s\": %s",
+  "893": "The \"sassOptions.functions\" option is not supported when using Turbopack. Custom Sass functions are only available with webpack. Please remove the \"functions\" property from your sassOptions in %s."
 }

filename: packages/next/src/server/config.ts
patch: @@ -378,6 +378,19 @@ function assignDefaultsAndValidate(
     )
   }
 
+  // Validate sassOptions.functions is not used with Turbopack
+  if (
+    process.env.TURBOPACK &&
+    result.sassOptions &&
+    'functions' in result.sassOptions
+  ) {
+    throw new Error(
+      `The "sassOptions.functions" option is not supported when using Turbopack. ` +
+        `Custom Sass functions are only available with webpack. ` +
+        `Please remove the "functions" property from your sassOptions in ${configFileName}.`
+    )
+  }
+
   if (isStableBuild()) {
     // Prevents usage of certain experimental features outside of canary
     if (result.experimental?.turbopackFileSystemCacheForBuild) {

filename: test/unit/isolated/config.test.ts
patch: @@ -102,6 +102,60 @@ describe('config', () => {
     )
   })
 
+  it('Should throw an error when sassOptions.functions is used with Turbopack', async () => {
+    const originalTurbopack = process.env.TURBOPACK
+    process.env.TURBOPACK = '1'
+
+    try {
+      await expect(async () => {
+        // Use a unique directory to avoid cache conflicts
+        await loadConfig(PHASE_DEVELOPMENT_SERVER, '<rootDir>-turbopack-test', {
+          customConfig: {
+            sassOptions: {
+              functions: {
+                'get($keys)': function (keys) {
+                  return 'test'
+                },
+              },
+            },
+          },
+        })
+      }).rejects.toThrow(
+        /The "sassOptions\.functions" option is not supported when using Turbopack/
+      )
+    } finally {
+      if (originalTurbopack === undefined) {
+        delete process.env.TURBOPACK
+      } else {
+        process.env.TURBOPACK = originalTurbopack
+      }
+    }
+  })
+
+  it('Should allow sassOptions.functions when not using Turbopack', async () => {
+    const originalTurbopack = process.env.TURBOPACK
+    delete process.env.TURBOPACK
+
+    try {
+      const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, '<rootDir>', {
+        customConfig: {
+          sassOptions: {
+            functions: {
+              'get($keys)': function (keys) {
+                return 'test'
+              },
+            },
+          },
+        },
+      })
+      expect((config as any).sassOptions.functions).toBeDefined()
+    } finally {
+      if (originalTurbopack !== undefined) {
+        process.env.TURBOPACK = originalTurbopack
+      }
+    }
+  })
+
   it('Should not throw an error when two versions of next.config.js are present', async () => {
     const config = await loadConfig(
       PHASE_DEVELOPMENT_SERVER,