-
-
Notifications
You must be signed in to change notification settings - Fork 722
Description
We (mostly) have a convention that we order imports in Rust code in order of "furthest away" to "closest".
The order
The full order is:
std- External crates
- Oxc crates
- Local crate (
crate) supermod
e.g.:
use std::{env, path::Path, sync::Arc};
use itertools::Itertools;
use rustc_hash::FxHashMap;
use oxc_allocator::Allocator;
use oxc_parser::Parser;
use oxc_semantic::{SemanticBuilder, dot::DebugDot};
use oxc_span::SourceType;
use crate::{Foo, Bar};
use super::{Qux, blah_blah::{example, words}};
mod something;
mod something_else;
pub use something::Thing;
use something_else::{AnotherThing, Stuff};Within each category, order should be alphabetical. rustfmt will enforce that.
"Oxc crates" means any crate whose name begins with oxc_. A few of those crates are outside of this monorepo e.g. oxc_index, but that is not relevant. They are still considered "Oxc crates".
Source priority
Imports should be imported from the closest available source.
- Prefer to
usefrom a localmodoversuperorcrate. - Prefer to
usefromsuperovercrate.
Example of good practice
// lib.rs
mod foo;
use foo::bar::Stuff;// foo/mod.rs
pub mod bar;
use bar::Stuff;// foo/bar.rs
pub struct Stuff {}Example of bad practice
// foo/mod.rs
use crate::Stuff;
pub mod stuff;Position of imports vs other code
All imports must be before all other code in the file. The only exceptions are:
- Module-level doc comments -
//! ... - Module-level attributes - e.g.
#![expect(clippy::print_stdout)]
Module-level doc comments should be at the very top of the file. Module-level attributes come next.
//! This module relates to blah.
#![expect(clippy::print_stdout)]
use std::mem;
pub struct Foo {
yeah: bool,
}Flexibility of the rules
The rules governing order are inflexible, except for 2 exceptions:
Feature gates
Sometimes it's clearer to break up feature-gated imports into a separate block.
use abc::def;
use xyz::zed;
#[cfg(feature = "serialize")]
use serde::Serialize;Note that serde is before xyz alphabetically, but appears here after xyz. That's OK, because we want to separate out the feature-gated import from the rest.
mod category
There can be some flexibility in the last category (mod statements, and use statements importing from those modules).
Sometimes it's better for readability to break up a lot of mod statements into multiple blocks, separate out pub use from use statements, or put line breaks between groups of statements that fit in these categories. This may make the code easier to read in some circumstances.
But the hard-and-fast rules concerning the last category are:
modmust always be before anyusestatements relating to thatmod.modmust always be after all other categories (afteruse crate::...,use super::...etc).
Line breaks
Note that there needs to be a line break in between the different categories of imports, otherwise rustfmt will re-order statements automatically, in a way which violates the above rules.
Additionally, any module-level attributes should have a line break between them and the first use statement:
#![expect(clippy::print_stdout)]
use std::mem;Ditto any module doc comments should have a line break after it before the first use:
//! This module relates to stuff.
use std::mem;Module-level doc comments and attributes should also be separated from each other by line breaks.
//! This module relates to stuff.
#![expect(clippy::print_stdout)]The last use / mod statement should have a line break after it, before any other code ("code" here includes comments or #[...] attributes).
use crate::Yeah;
/// Amazing data structure
#[derive(Debug)]
pub struct Amazing {
hell: Yeah,
}