Modules in Rust: How to Split Code into Multiple Files Without Losing Your Mind

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

When One File Is No Longer Enough

\n\n

You are writing in Rust. Your project is growing. Just yesterday, main.rs held everything — functions, structs, a couple of configs. And today you spend five minutes trying to find a specific function among a thousand lines. Sound familiar?

\n\n

Sooner or later, every Rust developer faces the need to split code into logical parts. It seems simple enough, right? Create a folder, arrange the files, import them — and you're done. But the Rust module system is known for its strictness. One wrong entry in mod.rs — and the compiler throws an error that will take you half an hour to figure out.

\n\n

In this article, we will break down the top errors when splitting a Rust module into multiple files and, most importantly, show you how to avoid them. You will learn how to properly organize your file structure, when to use mod.rs and when to use lib.rs, and why pub use is your best friend.

\n\n

Anatomy of the Rust Module System

\n\n

Before diving into the errors, let's recall the basics. In Rust, a module is a unit of code organization. By default, each file is a module, but it's not that straightforward.

\n\n

There are two approaches:

\n\n
    \n
  • File-as-module: The file utils.rs automatically becomes the utils module if you declare mod utils; in lib.rs or main.rs.
  • \n
  • Directory-as-module: A folder utils/ with a mod.rs file inside. In this case, mod.rs is the entry point to the module.
  • \n
\n\n

Sounds simple, but this is where most of the pitfalls lie. Let's break down the most common ones.

\n\n

Top 5 Errors When Splitting a Module into Multiple Files

\n\n

Error #1: Forgot to Declare a Submodule

\n\n

You created the file network/tcp.rs and are trying to use it. You write use network::tcp; — and get a compilation error. Why? Because Rust does not scan folders automatically. You must explicitly declare each submodule.

\n\n
// network/mod.rs\n// ❌ Error: submodule tcp is not declared\n// use network::tcp; // will not compile\n\n// ✅ Correct:\npub mod tcp; // declare the submodule\n
\n\n

How to avoid: Always check that you have added pub mod submodule_name; in the parent module. This is like an explicit import — Rust requires clarity.

\n\n

Error #2: Confusion Between mod.rs and lib.rs

\n\n

Beginners often place mod.rs in the project root, next to main.rs. This works, but only if you are creating a library. For an executable file (main.rs), the root module is main.rs itself. And mod.rs is a file inside a folder.

\n\n
my_project/\n├── main.rs        // root module for the binary\n├── lib.rs         // root module for the library (if any)\n├── utils/\n│   ├── mod.rs     // entry point for the utils module\n│   └── helpers.rs\n
\n\n

How to avoid: Remember the rule: mod.rs lives only inside a module folder. If you need a root module for a library — use lib.rs.

\n\n

Error #3: Forgot pub in Submodules

\n\n

You declared a submodule, but still cannot call a function. Most likely, you forgot to specify pub.

\n\n
// network/mod.rs\npub mod tcp;\n\n// network/tcp.rs\n// ❌ Function is private by default\nfn connect() { /* ... */ }\n\n// ✅ Make it public\npub fn connect() { /* ... */ }\n
\n\n

In Rust, everything is private by default. This is not a bug, but a feature: you decide what to expose to the outside world. If a function is needed outside the module — add pub.

\n\n

How to avoid: Use pub intentionally. For internal utilities, keep them private. For an API, make them public.

\n\n

Error #4: Ignoring

Blogs

Book Recommendations