Question
How to Import Modules from Another File in Rust Cargo Projects
Question
In a Rust Cargo project, how do you move a module into a separate file and use it from main.rs?
For example, this works when everything is in one file:
fn main() {
hello::print_hello();
}
mod hello {
pub fn print_hello() {
println!("Hello, world!");
}
}
But after splitting the code into two files like this:
src/
├── hello.rs
└── main.rs
src/main.rs
use hello;
fn main() {
hello::print_hello();
}
src/hello.rs
mod hello {
pub fn print_hello() {
println!("Hello, world!");
}
}
running cargo build gives this error:
error[E0432]: unresolved import `hello`
And trying extern crate hello; also fails with:
error[E0463]: can't find crate for `hello`
What is the correct way to include a module from another file in the same Rust project?
Short Answer
By the end of this page, you will understand how Rust modules map to files, when to use mod versus use, why extern crate is the wrong tool for files in the same project, and how to correctly split code across main.rs and other source files in a Cargo project.
Concept
In Rust, modules organize code inside a crate. A Cargo binary project usually has src/main.rs as its crate root. Files such as src/hello.rs are not imported automatically just because they exist. You must declare them as modules.
The key idea is:
mod hello;tells Rust: there is a module namedhello, and its code is in another file.use hello;does not create the module. It only brings an existing path into scope.extern crate hello;is for linking another crate, not another file inside the same crate.
So when you split code into another file, the usual pattern is:
mod hello;
fn main() {
hello::print_hello();
}
and then in src/hello.rs:
pub fn print_hello() {
println!("Hello, world!");
}
This matters because real Rust applications are almost always split into multiple files and modules. Understanding Rust's module system helps you structure projects cleanly, reuse code, and avoid import errors.
Mental Model
Think of a Rust crate like a building:
main.rsis the front desk.- Each module is a room.
- A file like
hello.rsis the contents of one room. mod hello;is the sign that tells the building, "This room exists; go load it."use hello::print_hello;is like saying, "I want quick access to this item from that room."extern crateis for bringing in a completely different building next door.
If you only write use hello;, that is like asking for directions to a room that was never registered in the building directory.
Syntax and Examples
Basic syntax
Declare a module from another file
In src/main.rs:
mod hello;
fn main() {
hello::print_hello();
}
In src/hello.rs:
pub fn print_hello() {
println!("Hello, world!");
}
Why this works
mod hello;loads thehellomodule fromsrc/hello.rspub fnmakes the function public to its parent modulehello::print_hello()calls the function through the module path
Using use for convenience
You can also bring the function into scope:
In src/main.rs:
Step by Step Execution
Consider this working example:
src/main.rs
mod hello;
fn main() {
hello::print_hello();
}
src/hello.rs
pub fn print_hello() {
println!("Hello, world!");
}
What happens step by step
- Rust starts at
main.rsbecause this is a binary crate. - It sees
mod hello;. - Rust looks for the module source in
src/hello.rs. - It loads that file as the contents of the
hellomodule. - Inside
main, Rust resolveshello::print_hello(). - Because
print_hellois markedpub, it is accessible frommain.rs. - The program runs and prints:
Real World Use Cases
Rust modules are used everywhere in real projects:
Splitting features into files
A command-line app might use:
main.rsfor startupconfig.rsfor configuration loadingparser.rsfor argument parsinglogger.rsfor logging helpers
Organizing web servers
A web application might have:
routes.rsfor HTTP route handlersmodels.rsfor data typesdb.rsfor database functionsauth.rsfor authentication logic
Reusing utility code
You may place helper functions in files such as:
string_utils.rsmath.rsfile_io.rs
Then use them from main.rs or other modules.
Keeping code maintainable
As code grows, one large file becomes hard to read. Modules help by:
Real Codebase Usage
In real Rust codebases, developers use modules to create clear boundaries between parts of the program.
Common patterns
1. Feature-based modules
mod auth;
mod config;
mod db;
mod routes;
Each file owns one responsibility.
2. use for cleaner call sites
Instead of writing full paths everywhere:
mod hello;
use hello::print_hello;
fn main() {
print_hello();
}
3. Public API with pub
Functions, structs, and enums are private by default. Developers choose what to expose:
pub fn connect() {}
fn internal_helper() {}
4. Nested modules for structure
Larger projects often use directories:
src/
├── main.rs
└── services/
├── mod.rs
└── email.rs
Common Mistakes
1. Using use instead of mod
Broken:
use hello;
fn main() {
hello::print_hello();
}
Why it fails:
useimports an existing path- it does not create or declare a module
Fix:
mod hello;
2. Using extern crate for your own file
Broken:
extern crate hello;
Why it fails:
extern craterefers to another crate dependencyhello.rsis just a module file in the current crate
Fix:
mod hello;
3. Wrapping the file in another mod hello {}
Comparisons
| Concept | Purpose | Used for | Example |
|---|---|---|---|
mod hello; | Declare a module | Load code from another file in the same crate | mod hello; |
use hello::print_hello; | Bring a path into scope | Shorter names for existing items | use hello::print_hello; |
extern crate foo; | Link another crate | Older style for external dependencies | extern crate serde; |
mod vs use
modcreates or declares the module in the crate structure
Cheat Sheet
Rust module quick reference
Same-project file module
src/main.rs
mod hello;
src/hello.rs
pub fn print_hello() {
println!("Hello, world!");
}
Call a function from the module
fn main() {
hello::print_hello();
}
Import for shorter usage
use hello::print_hello;
Rules to remember
- A file like
hello.rsusually corresponds to modulehello - Use
mod hello;to declare it - Use
use ...;to bring names into scope - Use
pubto expose items outside the module
FAQ
Why does use hello; not work in Rust?
Because use only imports an existing path into scope. It does not declare or load a module file. You need mod hello; first.
Do I need extern crate for another file in src/?
No. extern crate is for external crates, not files inside the same crate.
Why should hello.rs not contain mod hello { ... }?
Because hello.rs is already the hello module. Adding mod hello {} inside it creates an unnecessary nested module.
Why do I need pub on the function?
Items inside a module are private by default. pub makes the function accessible from main.rs.
Can I use use hello::print_hello;?
Yes, but only after the module exists. Usually that means declaring mod hello; first.
Mini Project
Description
Build a tiny Rust command-line program that separates greeting logic into its own module file. This demonstrates the correct way to declare a module from main.rs, expose a public function, and call it from the main program.
Goal
Create a Cargo project where main.rs loads a greetings.rs module and prints a message using a public function from that file.
Requirements
- Create a
greetings.rsfile insidesrc/ - Declare the module from
main.rs - Add a public function that returns or prints a greeting
- Call that function from
main - Make sure the program builds and runs with Cargo
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.
Default Function Arguments in Rust: What to Use Instead
Learn how Rust handles default function arguments, why they are not supported, and practical patterns to achieve similar behavior.
Fixing Rust "linker 'cc' not found" on Debian in WSL
Learn why Rust shows "linker 'cc' not found" on Debian in WSL and how to fix it by installing the required C build tools.