11 March 2026
Development
The Application Kit packages have been released with a new major version
v27.This guide provides detailed information about the migration process and necessary changes for Custom Applications and Custom Views to ensure a successful migration.
This release contains breaking changes. You must upgrade to ESLint 9 and replace your legacy
.eslintrc.* config file (for example, .eslintrc.js, .eslintrc.cjs, or .eslintrc.json) with eslint.config.js.Note that the following packages ship a
migrations/ directory with a version-specific upgrade guide available locally after installing:node_modules/@commercetools-frontend/eslint-config-mc-app/migrations/v27.mdnode_modules/@commercetools-backend/eslint-config-node/migrations/v27.md
These guides work as plain documentation or can be handed directly to an AI coding assistant:
Migrate my ESLint config following node_modules/@commercetools-frontend/eslint-config-mc-app/migrations/v27.md
Preparation
Before starting, we recommend reviewing the official ESLint 9 migration guide to understand the key changes introduced in this major version.
Config file
Replace your
.eslintrc.js file with eslint.config.js. The flat config format exports an array of config objects rather than a single object with extends and overrides.// BEFORE (.eslintrc.js)
module.exports = {
root: true,
extends: ['@commercetools-frontend/eslint-config-mc-app'],
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
rules: { /* ... */ },
},
],
};
// AFTER (eslint.config.js)
const mcAppConfig = require('@commercetools-frontend/eslint-config-mc-app');
module.exports = [
...mcAppConfig,
{
files: ['**/*.ts', '**/*.tsx'],
rules: { /* ... */ },
},
];
Plugins
Flat config requires actual plugin objects rather than string-based plugin names.
// BEFORE
module.exports = {
plugins: ['import', 'jsx-a11y'],
};
// AFTER
const importPlugin = require('eslint-plugin-import');
const jsxA11yPlugin = require('eslint-plugin-jsx-a11y');
module.exports = [
{
plugins: {
import: importPlugin,
'jsx-a11y': jsxA11yPlugin,
},
},
];
Parser
The parser is now specified in
languageOptions as an imported module rather than a string path.// BEFORE
module.exports = {
parser: '@babel/eslint-parser',
};
// AFTER
const babelParser = require('@babel/eslint-parser');
module.exports = [
{
languageOptions: {
parser: babelParser,
},
},
];
Globals
The
env property is replaced by the globals package spread into languageOptions.globals.// BEFORE
module.exports = {
env: { browser: true, node: true, jest: true },
};
// AFTER
const globals = require('globals');
module.exports = [
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
// Jest globals are now automatically scoped to test files
// (**/*.{spec,test}.*) by the config package.
},
},
},
];
Ignore patterns
The
.eslintignore file is no longer supported. Move ignore patterns directly into eslint.config.js.// BEFORE (.eslintignore)
dist/
coverage/
*.generated.js
// AFTER (eslint.config.js)
module.exports = [
{
ignores: ['dist/', 'coverage/', '*.generated.js'],
},
// ...rest of config
];
Dependency upgrades
The following dependencies were updated as part of this migration:
| Package | Before | After | Reason |
|---|---|---|---|
@typescript-eslint/* | ^5.62.0 | ^8.0.0 | v5 incompatible with ESLint 9 plugin API |
eslint-plugin-jest | ^27.2.3 | ^28.0.0 | v27 uses deprecated APIs removed in ESLint 9 |
eslint-plugin-react-hooks | ^4.6.0 | ^5.0.0 | v4 designed for ESLint 8 only |
eslint-plugin-testing-library | ^5.11.1 | ^7.0.0 | v7 uses @typescript-eslint/utils v8 |
globals | — | ^15.15.0 | Required for explicit global definitions in flat config |
@rushstack/eslint-patch | present | removed | ESLint 8 workaround, not needed in ESLint 9 |
Migration warnings
If your project still uses a legacy
.eslintrc.* file, the config packages will print an actionable warning at load time pointing to the migration guide. Projects already using eslint.config.js will see no output.