Skip to content
| Marketplace
Sign in
Visual Studio Code>Formatters>Rust Organize Import toolNew to Visual Studio Code? Get it now.
Rust Organize Import tool

Rust Organize Import tool

hugomartinezf

|
12 installs
| (0) | Free
Organize, sort, group, and auto-import Rust use statements
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Rust Import Organizer

A VS Code extension that automatically organizes Rust use statements — removing unused and duplicate imports, grouping by category, sorting alphabetically, and auto-importing missing symbols with disambiguation.

Features

  • Unused import removal — removes imports that are never referenced, with partial filtering for grouped imports (use std::path::{Path, PathBuf} becomes use std::path::Path; if only Path is used)
  • Duplicate removal — silently drops identical import statements
  • Flexible grouping — four modes to match any project style:
    • Standard (default) — three fixed sections: std / external / local, plus a fourth section for #[cfg(...)] conditional imports
    • Custom — define your own ordered groups by module prefix (e.g. put tokio and axum in their own groups)
    • Preserve — keep the blank-line groups you already have; only sort within each group
    • Flat — single block with no grouping
  • pub use placement — choose whether re-exports are mixed in inline, promoted to the top, or collected at the bottom
  • Alphabetical sorting — sorts imports by module path within each group
  • Auto-import with disambiguation — detects unresolved symbols and adds missing imports via Rust Analyzer; shows a QuickPick when multiple candidates exist so you can choose the right one
  • Organize on save — optionally runs automatically every time you save a .rs file
  • Cargo.toml awareness — reads your Cargo.toml to correctly classify workspace members as local rather than external
  • Implicit trait detection — keeps trait imports like sqlx::Row and anyhow::Context that are needed for method dispatch but never appear as bare identifiers
  • Comment preservation — // use ... and /* ... */ comment lines inside the import block are left exactly where they are; only real use statements are moved
  • Alias support — correctly handles use serde_json::Value as JsonValue;
  • Wildcard support — use module::* imports are always preserved
  • pub use support — re-exports are parsed and formatted correctly
  • Nested brace expansion — use std::{io::{Read, Write}, fs::File} is expanded and reorganized cleanly
  • Mid-file pub use detection — warns when it finds re-export statements outside the import block that the organizer cannot safely touch

Usage

Commands

Command Description
Organize Rust Imports Sort, group, deduplicate, and remove unused imports
Organize Rust Imports + Auto Import Same as above, plus auto-import any unresolved symbols first

Run either command from the Command Palette (Ctrl+Shift+P / Cmd+Shift+P) or right-click inside any Rust file.

Keyboard shortcut

Platform Shortcut
Windows / Linux Shift+Alt+O
macOS Shift+Option+O

Organize on save

Add to your settings.json to run automatically every time you save:

{
  "rust-import-organizer.organizeOnSave": true
}

Or use VS Code's built-in Code Actions on save (works with source.organizeImports):

{
  "[rust]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "explicit"
    }
  }
}

Auto-import disambiguation

When a symbol matches more than one crate, a QuickPick appears so you can pick the right one — the same UX as the Java extension. Symbols with exactly one match are applied automatically.

Requires the Rust Analyzer extension.

Example

Before

use std::sync::Arc;
use crate::internal::module;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::File;
use std::path::{Path, PathBuf};
use crate::config::Settings;
use tokio::runtime::Runtime;
use anyhow::Result;
#[cfg(test)]
use crate::test_helpers::setup;

After (default grouping)

The extension removes unused imports, groups, sorts, and preserves conditional imports last:

use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use anyhow::Result;
use tokio::runtime::Runtime;

use crate::config::Settings;

#[cfg(test)]
use crate::test_helpers::setup;

Arc, Serialize, Deserialize, PathBuf, and module were removed as unused. use std::path::{Path, PathBuf} was narrowed to use std::path::Path;. The #[cfg(test)] import is kept unconditionally and placed last.

After (custom group order)

With "importOrder": ["std", "tokio", "axum", "*", "crate"]:

use std::collections::HashMap;
use std::fs::File;

use tokio::runtime::Runtime;

use axum::Router;

use anyhow::Result;
use serde::Serialize;

use crate::config::Settings;

Configuration

{
  "rust-import-organizer.groupImports": true,
  "rust-import-organizer.importOrder": [],
  "rust-import-organizer.pubUsePlacement": "inline",
  "rust-import-organizer.sortAlphabetically": true,
  "rust-import-organizer.blankLineBetweenGroups": true,
  "rust-import-organizer.collapseSingleImports": false,
  "rust-import-organizer.removeUnused": true,
  "rust-import-organizer.enableAutoImport": true,
  "rust-import-organizer.organizeOnSave": false
}
Setting Type Default Description
groupImports true | false | "preserve" | "custom" true Controls how imports are grouped (see below)
importOrder string[] [] Ordered prefix list for custom grouping. Only used when groupImports is "custom"
pubUsePlacement "inline" | "first" | "last" "inline" Where pub use re-exports are placed
sortAlphabetically boolean true Sort by module path within each group
blankLineBetweenGroups boolean true Insert a blank line between each group
collapseSingleImports boolean false Collapse a grouped import filtered to one item (use std::path::{Path} → use std::path::Path;)
removeUnused boolean true Remove unused imports. Set to false to only sort and group
enableAutoImport boolean true Auto-import unresolved symbols when running Organize + Auto Import
organizeOnSave boolean false Automatically organize imports on save

Features in detail

Grouping modes

groupImports: true (default) — three fixed groups in order: standard library first, external crates second, local imports third. A fourth group at the end holds any #[cfg(...)] conditional imports. Empty groups produce no blank lines.

groupImports: false — all imports in one flat sorted block with no group separators.

groupImports: "preserve" — the organizer detects the blank-line boundaries that already exist between your imports and treats each blank-separated block as a group. It only sorts alphabetically within each group; it never adds or removes blank lines. This is ideal for teams that already have an agreed import order and just want alphabetical sorting within their existing groups.

// Before (preserve mode)             // After (preserve mode)
use axum::Router;                     use axum::Router;
use tokio::runtime::Runtime;          use tokio::runtime::Runtime;
                              →
use serde::Serialize;                 use anyhow::Result;
use anyhow::Result;                   use serde::Serialize;

groupImports: "custom" — define your own groups using importOrder. Each entry is a module prefix; the first match wins. Three special tokens are available:

  • "std" — matches the entire standard library family (std::, core::, alloc::)
  • "crate" — matches all local imports (crate::, super::, self::)
  • "*" — catch-all for anything not matched by a named prefix

Example for an Axum/Tokio web service:

{
  "rust-import-organizer.groupImports": "custom",
  "rust-import-organizer.importOrder": ["std", "tokio", "axum", "tower", "*", "crate"]
}

This produces five groups: std, then tokio, then axum, then tower, then all other external crates, then local. Specific prefixes always beat *, so crate:: imports correctly land in the "crate" group even if "*" appears earlier in the list.

pub use placement

pub use re-exports can be awkward to place — they are neither purely internal nor purely external. Three options:

  • "inline" (default) — re-exports are classified by their module path and placed in the corresponding group alongside regular imports.
  • "last" — all pub use statements are collected into a dedicated group at the bottom of the import block, just above any #[cfg(...)] imports. Common in library crates that re-export their public API.
  • "first" — the pub use group appears at the very top, before std imports.

Unused import removal

The extension analyses all identifiers referenced after the import block and removes any use statement whose imported name never appears. For grouped imports it filters item by item — only unused items are dropped, the rest are kept.

Alias-aware: use serde_json::Value as JsonValue; is kept as long as JsonValue appears in the code, even if Value itself does not.

Qualified-context aware: an identifier that appears only in a qualified position like Foo::Bar is treated as an enum variant or associated item — not as a use of the imported name. This prevents false positives:

use chrono::{DateTime, Utc};   // removed — neither is used directly
enum Event { DateTime(i64) }   // this is a variant definition, not chrono::DateTime

cfg-gated imports are always kept. Their usage cannot be determined statically because they are conditionally compiled.

Implicit trait method awareness: some traits must be in scope for method calls to work even though the trait name never appears explicitly in code. The extension detects characteristic call patterns and keeps the corresponding imports:

Pattern in code Import kept
.get("field") on a query result sqlx::Row
.execute(…) / fetch_one / fetch_all sqlx::Executor
.read(…) / read_to_string / read_to_end std::io::Read
.write(…) / write_all / flush() std::io::Write
.lines() / read_line std::io::BufRead
.seek(…) std::io::Seek
.context(…) / .with_context(…) anyhow::Context

String literals and comments are ignored during identifier scanning — "HashMap is useful" or /// Uses a HashMap will not prevent std::collections::HashMap from being removed if HashMap is not used in real code.

Comment preservation: comments that sit inside the import block — both // line comments and /* */ block comments — are left exactly where they are. Only real use statements are moved:

use std::fs::File;
// use std::io::Read;   ← left in place, never touched
use std::collections::HashMap;

Standard library family

std, core, and alloc are all treated as the standard library. core is the dependency-free subset of std; alloc adds heap allocation. Both are shipped with every Rust toolchain and belong in the std group alongside std:: imports.

Conditional imports (#[cfg(...)])

Imports preceded by a #[cfg(...)] attribute are placed in a dedicated fourth group at the end of the import block, each with its attribute on the preceding line:

// regular imports (std / external / local) ...

#[cfg(test)]
use crate::test_helpers::setup;

#[cfg(feature = "serde")]
use serde::Serialize;

Cargo.toml awareness

The extension reads your workspace Cargo.toml to build an accurate list of external dependencies and workspace members. This ensures workspace members are correctly classified as local imports rather than external crates, even when they do not use a crate:: prefix.

Nested brace expansion

use std::{io::{Read, Write}, fs::File};

is expanded into separate logical imports before processing:

use std::fs::File;
use std::io::{Read, Write};

Mid-file pub use detection

If a pub use or #[cfg]-guarded use statement appears after the main import block (e.g. a re-export accidentally placed at the bottom of a file), the extension cannot remove it automatically — it may be inside a mod block or otherwise intentional. Instead it shows a warning notification with the line number so you can review it manually.

Limitations

Trait method detection

The extension uses pattern-based detection to keep trait imports needed for method dispatch. It converts PascalCase trait names to snake_case method names (e.g., IntoResponse → into_response()). This approach has known limitations:

  • Naming convention dependency — The detection only works when the trait name directly maps to the method name. Traits like IntoResponse → .into_response() work, but traits with non-standard names (e.g., FromStr → .parse()) are not automatically detected.

  • Method name collisions — Common method names like .to_string(), .into(), .from() may match multiple traits. The extension conservatively keeps imports in these cases to avoid false removals.

  • Generic trait bounds — Traits used only as generic bounds (e.g., T: Into<String>) where the trait name never appears explicitly in code cannot be detected.

  • Operator traits — Traits like Add, Sub, Mul (used via operator overloading a + b) are not detected.

  • Future-proofing — The extension may not detect traits added in newer Rust editions or third-party crates that don't follow conventional naming.

If you encounter a case where a needed trait import is incorrectly removed, please open an issue. You can also set "rust-import-organizer.removeUnused": false in your settings to disable unused import removal entirely while the team works on a fix.

Development

For detailed development instructions, testing procedures, and contribution guidelines, see DEVELOPMENT.md.

For quick reference and common tasks, see QUICKSTART.md.

License

MIT

Contributing

Pull requests are welcome. Please open an issue first to discuss significant changes.

Issues

Report bugs or request features on the GitHub Issues page.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft