Question
In Rust, what is the difference between use and extern crate?
My current understanding is that use imports identifiers into the current scope, while extern crate declares an external crate. However, that distinction does not fully make sense to me.
Why does Rust have these two concepts, and when should each one be used?
Short Answer
By the end of this page, you will understand what use does, what extern crate historically did, why Rust had both, and how modern Rust code usually works without extern crate. You will also see practical examples, common mistakes, and how imports are typically written in real Rust projects.
Concept
use and extern crate are related, but they solve different problems.
The core idea
extern cratewas historically used to make an external crate available to your crate.usebrings names from a module or crate path into the current scope.
In other words:
extern crateconnected your program to another crate.usemade specific items easier to refer to.
Why this existed
Rust has a module system with paths, similar to file paths or namespaces in other languages. A path like std::io::Result tells Rust exactly where an item lives.
Originally, Rust required an explicit step to say:
"This external crate exists and I want to link it into my crate."
That step was extern crate.
Then, once the crate was available, use could bring names from it into scope:
extern crate rand;
use rand::Rng;
Here:
extern crate rand;made therandcrate available.
Mental Model
Think of a crate like a building, and names inside it like rooms.
extern crateis like registering that the building is part of your campus.useis like putting a shortcut sign on your desk so you can quickly refer to a room inside that building.
Example:
- Without a shortcut, you might write the full path every time.
- With
use, you can write a shorter name.
So:
extern crate= make the outside library availableuse= bring a name into your local working area
In modern Rust, Cargo and the 2018 edition handle much of the "register the building" step for you automatically, so you mostly just write the shortcut with use.
Syntax and Examples
Basic syntax
Using use
use std::collections::HashMap;
This brings HashMap into the current scope, so you can write:
let map = HashMap::new();
instead of:
let map = std::collections::HashMap::new();
Using extern crate in older Rust
extern crate rand;
use rand::Rng;
This was the old style for external crates.
Example: use only in modern Rust
use std::collections::HashMap;
fn main() {
let mut = HashMap::();
scores.(, );
scores.(, );
(, scores);
}
Step by Step Execution
Consider this example:
use std::collections::HashMap;
fn main() {
let mut counts = HashMap::new();
counts.insert("apple", 2);
counts.insert("banana", 3);
println!("{:?}", counts);
}
Step by step
1. use std::collections::HashMap;
Rust sees that you want the name HashMap available in this scope.
After this line, inside the current module, HashMap can be used as a short name for std::collections::HashMap.
2. let mut counts = HashMap::new();
Rust resolves HashMap using the use statement.
This is effectively the same as writing:
= std::collections::HashMap::();
Real World Use Cases
Where use is used constantly
Importing types
use std::fs::File;
use std::io::Read;
Used when working with files and input/output.
Importing traits
use rand::Rng;
Needed so trait methods become available.
Importing enums or variants
use std::cmp::Ordering;
Useful for matching comparison results.
Shortening long paths
use crate::services::user_service::UserService;
Common in larger applications with nested modules.
Where extern crate appears today
Mostly in:
- older Rust codebases
- old blog posts and tutorials
- legacy crates written before Rust 2018
- a few niche compatibility situations
If you are starting a new Rust project, you will usually not need it.
Real Codebase Usage
In real Rust projects, use is part of everyday code organization.
Common patterns
1. Grouping imports at the top of a file
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
This makes dependencies of the module easy to scan.
2. Importing your own modules with crate::
use crate::config::Settings;
use crate::errors::AppError;
This is very common in application code.
3. Bringing traits into scope for methods
use std::io::Read;
Without the trait import, method calls provided by the trait may not resolve.
4. Aliasing to avoid naming conflicts
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;
Useful when two modules export items with the same name.
5. Nested import syntax
Common Mistakes
1. Thinking use loads or links a crate
use does not mean "download this library" or "link this crate." It only introduces a name into scope.
Broken assumption:
use some_crate::Thing;
This only works if some_crate is actually available as a dependency.
2. Thinking extern crate imports everything automatically
Older Rust code like this:
extern crate rand;
does not put all of rand into local scope. You still need full paths or use:
extern crate rand;
use rand::Rng;
3. Forgetting to import a trait
This is very common.
Broken code:
fn main() {
= rand::();
= rng.(..=);
(, n);
}
Comparisons
use vs extern crate
| Feature | use | extern crate |
|---|---|---|
| Main purpose | Bring names into scope | Make an external crate available in older Rust |
| Used in modern Rust | Yes, constantly | Rarely |
| Works with local modules | Yes | No |
| Works with external crates | Yes | Historically yes |
| Shortens long paths | Yes | No |
| Usually needed today | Yes | Usually not |
Full path vs use
Cheat Sheet
Quick reference
Modern Rust
- Add external crates in
Cargo.toml - Use
useto bring names into scope - Usually do not write
extern crate
use
use std::collections::HashMap;
use std::io::{self, Read};
use crate::config::Settings;
use rand::Rng;
Old style extern crate
extern crate rand;
use rand::Rng;
What use can import
- types
- functions
- modules
- traits
- enum names
- enum variants with extra syntax
Important rule
use affects the current scope only.
Trait reminder
If a method comes from a trait, you often need the trait in scope:
FAQ
Why does modern Rust usually not need extern crate?
Rust 2018 improved the module system so crates in Cargo.toml are generally available directly by name.
Is extern crate deprecated?
It is mostly unnecessary in modern Rust, but you may still see it in older code and some special cases.
Does use install a crate?
No. Dependencies are declared in Cargo.toml. use only brings names into scope in source code.
Can I use use with my own modules?
Yes. For example:
use crate::models::User;
Why do I sometimes need use some_trait::TraitName?
Because methods provided by traits are often only usable when the trait is in scope.
Should I remove extern crate from old code?
If the project uses Rust 2018 or later, you can often simplify imports by removing it, but test carefully after changes.
What is the difference between use and a full path?
Mini Project
Description
Build a small Rust program that uses both standard library imports and an external crate import. This project demonstrates the modern Rust import style and helps you see how use works in practice without relying on extern crate.
Goal
Create a command-line program that generates a random number and stores a few values in a HashMap using use imports.
Requirements
- Add the
randcrate toCargo.toml - Import
HashMapfrom the standard library withuse - Import the
Rngtrait so random number methods work - Store at least three key-value pairs in a
HashMap - Generate and print one random number
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Convert an Integer to a String in Rust
Learn the current Rust way to convert integers to strings, why `to_str()` no longer works, and when to use `to_string()` or `format!`.