> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---
id: 889e0715-a71c-4d7e-a336-39304416c00c
---

# Migrating to v1.0 (ESLint 9)

> Migrate an existing ESLint configuration to ESLint 9.

Version 1.0 is a major update that moves to ESLint 9's [flat config format](https://eslint.org/docs/latest/use/core-concepts/glossary#flat-config) and unbundles third-party rules to give you more control over your linting setup. The flat config files don't allow nesting configuration files in subdirectories -- instead, all nesting must be in one configuration file.

If you already have an ESLint configuration in your project, review the table below to see what's changed:

| Before (v0.x)                                   | After (v1.0)                        |
| ----------------------------------------------- | ----------------------------------- |
| ESLint 8                                        | ESLint 9+ required                  |
| Legacy config (`.eslintrc.*`)                   | Flat config (`eslint.config.js`)    |
| Bundled `eslint:recommended`                    | Install separately via `@eslint/js` |
| Bundled `eslint-plugin-react` recommended rules | Install and configure separately    |
| Bundled `eslint-plugin-react-hooks`             | Install and configure separately    |
| Bundled `eslint-config-prettier`                | Install and configure separately    |
| CommonJS (`require()`)                          | ESM (`import`)                      |

After reviewing the above changes, proceed with the steps below to migrate to the latest version.

## Migrate your ESLint config

### 1. Review your current config

Before migrating, open your existing `.eslintrc.*` file and note:

* Any custom `rules` you've added or modified
* Any additional `plugins` you're using
* Any `overrides` for specific file patterns
* Any `env` or `globals` settings

You'll need to translate these to flat config format. Keep your old config file for reference until migration is complete.

### 2. Update dependencies

Upgrade to ESLint 9 and the new package version by running the following command:

```shell theme={null}
npm i --save-dev eslint@^9 @hubspot/eslint-config-ui-extensions@^1
```

### 3. Set up ESM

ES modules is required for a flat configuration, so you'll need to ensure your `package.json` includes `"type": "module"`:

```json theme={null}
{
  "type": "module"
}
```

### 4. Create a new ESLint config file

Create an `eslint.config.js` file in your project root. Start with either the minimal or recommended setup below, then add your custom rules. Read more about each addition in the [Recommended setup section of the overview](/apps/developer-platform/add-features/ui-extensions/tools/linting/overview#recommended-setup).

**Minimal setup** (HubSpot UI extensions rules only):

```js theme={null}
import { config } from '@hubspot/eslint-config-ui-extensions';

export default [
  ...config,
  // Add your custom rules here (see Step 5)
];
```

**Recommended setup** (replaces previously bundled configs, plus extras):

```shell theme={null}
npm i --save-dev @eslint/js typescript-eslint eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier eslint-plugin-unused-imports
```

```js theme={null}
import { defineConfig } from 'eslint/config';
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import unusedImports from 'eslint-plugin-unused-imports';
import prettier from 'eslint-config-prettier';
import { config as uiExtensionsConfig } from '@hubspot/eslint-config-ui-extensions';

export default defineConfig([
  js.configs.recommended,
  tseslint.configs.recommended,
  tseslint.configs.stylistic,
  react.configs.flat.recommended,
  react.configs.flat['jsx-runtime'],
  {
    settings: {
      react: { version: 'detect' },
    },
  },
  ...uiExtensionsConfig,
  reactHooks.configs.flat['recommended-latest'],
  {
    plugins: {
      'unused-imports': unusedImports,
    },
    rules: {
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': 'off',
      'unused-imports/no-unused-imports': 'error',
      'unused-imports/no-unused-vars': [
        'warn',
        {
          vars: 'all',
          varsIgnorePattern: '^_',
          args: 'after-used',
          argsIgnorePattern: '^_',
        },
      ],
      'react/prop-types': 'off',
    },
  },
  prettier,
  // Add your custom rules here (see Step 5)
]);
```

### 5. Migrate your custom configuration

Refer to your old config file and translate your customizations to flat config format.

Custom rules:

```js theme={null}
// Before (.eslintrc.js)
module.exports = {
  rules: {
    'no-console': 'warn',
    'prefer-const': 'error',
  },
};

// After (eslint.config.js) - add to your config array
{
  rules: {
    'no-console': 'warn',
    'prefer-const': 'error',
  },
}
```

Overrides (file-specific rules):

```js theme={null}
// Before (.eslintrc.js)
module.exports = {
  overrides: [
    {
      files: ['*.test.js'],
      rules: {
        'no-console': 'off',
      },
    },
  ],
};

// After (eslint.config.js) - add to your config array
{
  files: ['**/*.test.js'],
  rules: {
    'no-console': 'off',
  },
}
```

Globals:

```js theme={null}
// Before (.eslintrc.js)
module.exports = {
  globals: {
    myGlobal: 'readonly',
  },
};

// After (eslint.config.js) - add to your config array
{
  languageOptions: {
    globals: {
      myGlobal: 'readonly',
    },
  },
}
```

Environments:

Flat config uses `globals` instead of `env`.

```js theme={null}
// Before (.eslintrc.js)
module.exports = {
  env: {
    browser: true,
    node: true,
  },
};

// After (eslint.config.js)
import globals from 'globals';

export default [
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      },
    },
  },
  // ... rest of config
];
```

For more details, see the [official ESLint migration guide](https://eslint.org/docs/latest/use/configure/migration-guide).

### 6. Testing and cleanup

Run ESLint to verify your migration:

```shell theme={null}
npm run lint
```

Once you've verified that everything works, you can delete your old `.eslintrc.*` file.

## Troubleshooting

### ESLint seems to ignore your new config

ESLint 9 looks for `eslint.config.js` by default and ignores `.eslintrc.*` files. If it seems like ESLint is ignoring your new config, make sure:

1. You created `eslint.config.js` in your project root.
2. The file is correctly exporting an array (check for syntax errors).

### Error: Cannot use require() to import an ES module

Your config file is being loaded as CommonJS. Make sure:

1. Your `package.json` has `"type": "module"`.
2. Your config file is named `eslint.config.js` (not `.cjs`).

### Errors about missing plugins or rules

If you see errors like `Definition for rule 'react/prop-types' was not found`, you're using a rule from a plugin that was previously bundled but is now opt-in. Either:

1. Install the plugin and add it to your config (see [recommended setup](/apps/developer-platform/add-features/ui-extensions/tools/linting/overview#recommended-setup)).
2. Remove the rule if you no longer need it.

### Error: Invalid option 'extends'

Flat config uses a different structure than legacy config. You can't use `extends`, `env`, `plugins` (as an array), or `overrides` the same way. See [Step 5 above](#5-migrate-your-custom-configuration) for translation examples.
