| | |

Prettier 27 ๐ŸŽจ Import Sorting Plugins โ€” @ianvs/prettier-plugin-sort-imports & alternatives

โฑ๏ธ Estimated read: 11 min | |

Prettier does not sort imports. It formats the imports that exist, but it leaves their order exactly as written. The sorting is a separate concern, and it is provided by plugins. The three that matter are @trivago/prettier-plugin-sort-imports, which is the original regex-based sorter, @ianvs/prettier-plugin-sort-imports, which is a fork of the original with safer defaults, and prettier-plugin-organize-imports, which is not a sorter in the same senseโ€”it runs the TypeScript language service’s “Organize Imports” action, which sorts and also removes unused imports . The choice between them is a choice about safety, not about features.

The @ianvs plugin is the one the comparison articles recommend for a project that wants a custom import order. It does not move side-effect imports, it merges duplicate imports from the same module, and it requires less configuration than the trivago original . The trivago plugin is the original, it is still maintained, and its configuration is the one that most existing projects use. The organize-imports plugin is the zero-config option, but it has a critical limitation: with TypeScript 7, it silently does nothing . The limitation is the reason the plugin is not a general recommendation, even though it is the only one that removes unused imports.

Key point: @ianvs/prettier-plugin-sort-imports is the safer fork of the trivago plugin. It preserves side-effect imports, merges duplicate imports, and supports the <TYPES> and <BUILTIN_MODULES> special words. prettier-plugin-organize-imports removes unused imports but is incompatible with TypeScript 7. The trivago plugin is the original and is still maintained.


Why the sorting plugins are separate from Prettier

The opinionated formatter problem. Prettier’s design philosophy is to make formatting decisions and to make very few of them configurable. The order of imports is a decision that varies by projectโ€”some projects want React first, some want built-ins first, some want CSS at the bottom. Prettier does not want to own that decision, so it leaves the imports in place and exposes a plugin API for the projects that want to sort them . The plugin is the mechanism that adds the sorting without adding the opinion to Prettier itself.

The side-effect problem. Not all imports are safe to reorder. An import that does not bind a nameโ€”import './polyfills' or import './styles.css'โ€”is a side-effect import, and its order can affect the runtime. The CSS cascade depends on the order of the CSS imports, and a polyfill must load before the code that depends on it. The @ianvs plugin preserves the side-effect imports by default, and the trivago plugin moves them by default unless importOrderSideEffects is set to false . The difference is the reason the @ianvs plugin is the safer default for a new project.

The duplicate-import problem. A file can import from the same module more than onceโ€”a value import and a type import, or two separate imports that were added at different times. The @ianvs plugin merges the imports when it is safe, and the trivago plugin does not . The merging is a formatting improvement, but it is also a semantic decision: merging a type import and a value import changes the output syntax, and the @ianvs plugin has a importOrderTypeScriptVersion option that controls whether the merging is enabled based on the project’s TypeScript version .

The trade-off. The @ianvs plugin is the safer choice, but it is a fork, and a fork carries a maintenance risk that the original does not. The trivago plugin has a larger download count and a longer history, and it is the one that the ant-design project used before switching to the @ianvs fork . The organize-imports plugin is the only one that removes unused imports, but the TypeScript 7 incompatibility makes it unsuitable for a project that has upgraded. The choice is the trade-off between safety, maintenance, and features.


a. The @ianvs plugin configuration

The @ianvs plugin is configured with the importOrder array. The array contains regular expressions and special words. The default order is built-in modules, third-party modules, and relative imports .

// .prettierrc โ€” the @ianvs plugin
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrder": [
    "<BUILTIN_MODULES>",
    "<THIRD_PARTY_MODULES>",
    "^[.]"
  ]
}

The <BUILTIN_MODULES> and <THIRD_PARTY_MODULES> special words are the mechanism for the default groups. The <TYPES> special word is the mechanism for grouping type imports separately. The "" empty string is the mechanism for adding a blank line between groups .

// .prettierrc โ€” the @ianvs plugin with type grouping
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrder": [
    "<BUILTIN_MODULES>",
    "",
    "<THIRD_PARTY_MODULES>",
    "",
    "<TYPES>",
    "",
    "^[.]"
  ]
}

The <TYPES> word groups the type imports, and the empty strings add the blank lines between the groups. The importOrderSafeSideEffects option is the escape hatch for a side-effect import that is known to be safe to reorder, such as import "server-only" . The option accepts an array of regex patterns that match the side-effect imports that can be sorted.


b. The trivago plugin and the organize-imports plugin

The trivago plugin is the original, and its configuration is similar to the @ianvs plugin’s. The main difference is the side-effect behavior and the duplicate-import behavior.

// .prettierrc โ€” the trivago plugin
{
  "plugins": ["@trivago/prettier-plugin-sort-imports"],
  "importOrder": ["^react$", "<THIRD_PARTY_MODULES>", "^[.]"],
  "importOrderSeparation": true,
  "importOrderSortSpecifiers": true
}

The importOrderSeparation option is the blank-line mechanism, and the importOrderSortSpecifiers option is the named-import sorting mechanism . The importOrderSideEffects option is the side-effect behavior, and it defaults to true, which means the trivago plugin moves the side-effect imports by default . The importOrderCaseInsensitive option is the case-sensitivity control.

The organize-imports plugin is the different case. It does not use an importOrder array. It runs the TypeScript language service’s “Organize Imports” action, which sorts the imports alphabetically and removes the unused ones.

// .prettierrc โ€” the organize-imports plugin
{
  "plugins": ["prettier-plugin-organize-imports"]
}

The plugin’s value is the unused-import removal, which the other two plugins do not provide. The plugin’s limitation is the TypeScript 7 incompatibility: the plugin silently does nothing when the project is on TypeScript 7 . The limitation is the reason the article recommends it only for a project on TypeScript 6 or older.


Complete Example Session

// ============================================
// PART 1: THE @ianvs PLUGIN
// ============================================

// .prettierrc
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrder": [
    "<BUILTIN_MODULES>",
    "",
    "<THIRD_PARTY_MODULES>",
    "",
    "<TYPES>",
    "",
    "^[.]"
  ]
}

// The plugin sorts the imports and preserves the side-effect imports.

// ============================================
// PART 2: THE INPUT
// ============================================

// src/app.ts
import styles from './styles.css';
import { useState } from 'react';
import fs from 'node:fs';
import { Button } from './Button';
import type { User } from './types';

// The side-effect import (styles.css) is preserved in place.

// ============================================
// PART 3: THE OUTPUT
// ============================================

// src/app.ts (after formatting)
import fs from 'node:fs';

import { useState } from 'react';

import type { User } from './types';

import styles from './styles.css';
import { Button } from './Button';

// The built-in, third-party, type, and relative groups are separated.
// The side-effect import stays where it was.

// ============================================
// PART 4: THE TRIVAGO PLUGIN
// ============================================

// .prettierrc
{
  "plugins": ["@trivago/prettier-plugin-sort-imports"],
  "importOrder": ["^react$", "<THIRD_PARTY_MODULES>", "^[.]"],
  "importOrderSeparation": true,
  "importOrderSideEffects": false
}

// The importOrderSideEffects: false preserves the side-effect imports.
// The importOrderSeparation: true adds the blank lines.

// ============================================
// PART 5: THE ORGANIZE-IMPORTS PLUGIN
// ============================================

// .prettierrc
{
  "plugins": ["prettier-plugin-organize-imports"]
}

// The plugin removes the unused imports and sorts the rest.
// It does not use an importOrder array.
// It is incompatible with TypeScript 7.

// ============================================
// PART 6: THE COMPARISON
// ============================================

// @ianvs:    custom order, preserves side-effects, merges duplicates.
// trivago:   custom order, moves side-effects by default.
// organize:  alphabetical, removes unused, incompatible with TS 7.

// ============================================
// PART 7: THE SAFE-SIDE-EFFECTS OPTION
// ============================================

// .prettierrc โ€” the @ianvs plugin
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrderSafeSideEffects": ["^server-only$"]
}

// The server-only import can be sorted with the rest.
// The other side-effect imports are preserved.

// ============================================
// PART 8: THE TYPE GROUPING
// ============================================

// .prettierrc โ€” the @ianvs plugin with type grouping
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrder": [
    "<TYPES>^(node:)",
    "<TYPES>",
    "<TYPES>^[.]",
    "^[.]"
  ]
}

// The built-in types, third-party types, and local types
// are grouped separately.

// ============================================
// PART 9: THE OVERRIDES
// ============================================

// .prettierrc โ€” the @ianvs plugin with overrides
{
  "plugins": ["@ianvs/prettier-plugin-sort-imports"],
  "importOrder": ["<THIRD_PARTY_MODULES>", "^[.]"],
  "overrides": [
    {
      "files": "**/*.test.ts",
      "options": {
        "importOrder": ["^vitest", "<THIRD_PARTY_MODULES>", "^[.]"]
      }
    }
  ]
}

// The test files have a different order.

// ============================================
// PART 10: THE CHECKLIST
// ============================================

// [ ] The plugin is installed as a dev dependency.
// [ ] The plugin is in the Prettier plugins array.
// [ ] The importOrder array is configured.
// [ ] The side-effect behavior is verified.
// [ ] The type grouping is configured if needed.
// [ ] The TypeScript version is checked if organize-imports is used.

The ten parts covered the @ianvs plugin, the input, the output, the trivago plugin, the organize-imports plugin, the comparison, the safe-side-effects option, the type grouping, the overrides, and the checklist. The through-line is that the three plugins are different trade-offs, and the @ianvs plugin is the safer default.


Quick Reference

The three plugins

PluginCustom orderSide-effectsUnused importsTypeScript 7
@ianvsYesPreservedNoYes
@trivagoYesMoved (default)NoYes
organize-importsNo (alphabetical)MovedYesNo

The @ianvs special words

WordPurpose
<BUILTIN_MODULES>Node.js built-ins
<THIRD_PARTY_MODULES>Third-party packages
<TYPES>Type imports
""Blank line between groups

The options

OptionPluginPurpose
importOrderBothThe sort order
importOrderSeparationtrivagoBlank lines
importOrderSortSpecifierstrivagoNamed-import sorting
importOrderSafeSideEffects@ianvsSide-effect escape hatch

Best Practices

โœ… Do This:

// Use @ianvs for a new project
"plugins": ["@ianvs/prettier-plugin-sort-imports"]                 // โœ…
// Preserve the side-effect imports
// The @ianvs plugin preserves them by default.                    // โœ…
// Group the type imports separately
"importOrder": ["<TYPES>", "<THIRD_PARTY_MODULES>", "^[.]"]      // โœ…

โŒ Don’t Do This:

// Use organize-imports with TypeScript 7
"plugins": ["prettier-plugin-organize-imports"] // silently does nothing // โŒ
// Move the CSS imports with the trivago plugin
// The default moves them; set importOrderSideEffects: false.      // โŒ

Common Pitfalls

PitfallWhy It HappensFix
The side-effect imports moveThe trivago default moves themSet importOrderSideEffects: false
The plugin does nothingorganize-imports with TS 7Use @ianvs instead
The type imports are not grouped<TYPES> is not active by defaultAdd <TYPES> to importOrder
The CSS imports are in the wrong orderThe CSS cascade depends on the orderPreserve the side-effect imports

Real-World Examples

1. The @ianvs plugin

{ "plugins": ["@ianvs/prettier-plugin-sort-imports"] }

2. The trivago plugin

{ "plugins": ["@trivago/prettier-plugin-sort-imports"] }

3. The organize-imports plugin

{ "plugins": ["prettier-plugin-organize-imports"] }

4. The default order

"importOrder": ["<BUILTIN_MODULES>", "<THIRD_PARTY_MODULES>", "^[.]"]

5. The type grouping

"importOrder": ["<TYPES>", "<THIRD_PARTY_MODULES>", "^[.]"]

6. The safe side-effects

"importOrderSafeSideEffects": ["^server-only$"]

7. The trivago side-effect fix

"importOrderSideEffects": false

8. The overrides

"overrides": [{ "files": "**/*.test.ts", "options": { "importOrder": ["^vitest", "^[.]"] } }]

9. The React-first order

"importOrder": ["^react$", "<THIRD_PARTY_MODULES>", "^[.]"]

10. The CSS-bottom order

"importOrder": ["<THIRD_PARTY_MODULES>", "^(?!.*[.]css$)[./].*$", ".css$"]

Visual

The Three Plugins

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SORTING, SIDE-EFFECTS, AND UNUSED IMPORTS                    โ”‚
โ”‚                                                              โ”‚
โ”‚  @ianvs                     trivago              organize   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ Custom order        โ”‚   โ”‚ Custom orderโ”‚      โ”‚ Alpha   โ”‚ โ”‚
โ”‚  โ”‚ Side-effects kept   โ”‚   โ”‚ Side-effectsโ”‚      โ”‚ Unused  โ”‚ โ”‚
โ”‚  โ”‚ Duplicates merged   โ”‚   โ”‚ moved       โ”‚      โ”‚ removed โ”‚ โ”‚
โ”‚  โ”‚                     โ”‚   โ”‚             โ”‚      โ”‚         โ”‚ โ”‚
โ”‚  โ”‚ TS 7 compatible     โ”‚   โ”‚ TS 7        โ”‚      โ”‚ TS 7    โ”‚ โ”‚
โ”‚  โ”‚                     โ”‚   โ”‚ compatible  โ”‚      โ”‚ broken  โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Type Grouping

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  <TYPES> GROUPS THE TYPE IMPORTS                              โ”‚
โ”‚                                                              โ”‚
โ”‚  import type { User } from './types';                        โ”‚
โ”‚  import { useState } from 'react';                           โ”‚
โ”‚                                                              โ”‚
โ”‚  With <TYPES>:                                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                    โ”‚
โ”‚  โ”‚ import type { User }โ”‚  โ† type group                      โ”‚
โ”‚  โ”‚                     โ”‚                                    โ”‚
โ”‚  โ”‚ import { useState } โ”‚  โ† value group                     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Side-Effect Preservation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SIDE-EFFECT IMPORTS ARE NOT SAFE TO MOVE                     โ”‚
โ”‚                                                              โ”‚
โ”‚  import './styles.css';                                      โ”‚
โ”‚  import './polyfills';                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  The @ianvs plugin preserves the order by default.           โ”‚
โ”‚  The trivago plugin moves them unless configured.            โ”‚
โ”‚  The CSS cascade depends on the order.                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
@ianvsSafer fork, preserves side-effects, merges duplicates
@trivagoOriginal, moves side-effects by default
organize-importsRemoves unused imports, incompatible with TS 7
Special words<BUILTIN_MODULES>, <THIRD_PARTY_MODULES>, <TYPES>
Blank lines"" in importOrder
Side-effect escape hatchimportOrderSafeSideEffects

Key takeaways:

  • Prettier does not sort imports; the plugins do. The @ianvs plugin is the safer default for a new project because it preserves side-effect imports and merges duplicate imports. The trivago plugin is the original and is still maintained, but it moves side-effect imports by default .
  • The @ianvs plugin is a fork of the trivago plugin with safer defaults. It adds the <BUILTIN_MODULES> and <TYPES> special words, the duplicate-import merging, and the side-effect preservation. The trivago plugin has the larger download count and the longer history .
  • prettier-plugin-organize-imports is the only one that removes unused imports. It runs the TypeScript language service’s “Organize Imports” action, but it silently does nothing with TypeScript 7. A project on TypeScript 6 or older can use it; a project on TypeScript 7 cannot .
  • The side-effect imports are the safety boundary. A CSS import, a polyfill, or a server-only import has an order-dependent effect. The @ianvs plugin preserves the side-effect imports by default, and the importOrderSafeSideEffects option is the escape hatch for the ones that are known to be safe .
  • The <TYPES> special word groups the type imports. The option is not active by default, and it must be added to the importOrder array. The importOrderTypeScriptVersion option controls the syntax that the plugin emits for the type imports .

Remember: The import-sorting plugins are a choice about safety, not about features. The @ianvs plugin is the safer default because it preserves the side-effect imports and merges the duplicates. The trivago plugin is the original, and it is still maintained, but its default moves the side-effect imports. The organize-imports plugin is the only one that removes the unused imports, but the TypeScript 7 incompatibility makes it unsuitable for a modern project. The importOrder array is the configuration, and the special words are the groups. The side-effect imports are the boundary, and the @ianvs plugin respects it.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!