---
title: "13.2 Defining modules and paths"
description: "How to define nested modules, refer to items with absolute and relative paths (crate::, self::, super::), and bring names into scope with use."
url: "https://learnrust.net/chapter-13/defining-modules/"
last_updated: "2026-06-13"
---

# 13.2 Defining modules and paths

Lesson [13.1](https://learnrust.net/chapter-13/naming-collisions-and-modules/) introduced modules as named scopes. This lesson makes them practical: how to nest them, how to name something inside one (a **path**), and how to shorten those paths with `use`. We'll keep everything in a single file for now; splitting across files is lesson [13.4](https://learnrust.net/chapter-13/splitting-code-into-files/), and it changes nothing about the ideas here.

One thing up front: by default, everything inside a module is *private* to that module, so the examples below mark items `pub` to make them reachable from outside. That keyword is lesson [13.3](https://learnrust.net/chapter-13/visibility-pub/)'s whole subject; for now, read `pub` as "visible outside this module" and don't worry about the details.

## Nesting modules

Modules can contain other modules, which lets you build a tree that mirrors how you think about the program. A restaurant's front-of-house operations might nest like this:

```rust
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("added to waitlist");
        }
    }

    pub mod serving {
        pub fn take_order() {
            println!("order taken");
        }
    }
}
```

`front_of_house` contains `hosting` and `serving`, and each of those contains functions. This forms a tree, with the crate itself at the root (the implicit top-level module called `crate`), `front_of_house` as a child, and `hosting` and `serving` as its children. The structure is exactly the file-system metaphor it resembles: modules are folders, items are files, and a path names a location in the tree.

## Paths: naming items in the tree

To call `add_to_waitlist` from elsewhere, you write a **path** to it. There are two kinds. An **absolute path** starts from the crate root with the keyword `crate`:

```rust
fn main() {
    crate::front_of_house::hosting::add_to_waitlist();
}
```

A **relative path** starts from the current module. From the crate root, `front_of_house` is right there, so:

```rust
fn main() {
    front_of_house::hosting::add_to_waitlist();
}
```

Both reach the same function. Read a path left to right as a route through the tree: "from the crate root, into `front_of_house`, into `hosting`, to `add_to_waitlist`." It's the same `::` you've used since `String::from`; now you can see it was always a path through a module tree, the standard library's tree instead of your own.

## self and super

Two more path keywords navigate relative to where you are. `self::` means "starting from the current module" (rarely needed but explicit). `super::` means "starting from the parent module," the module-tree equivalent of `..` in a file path. `super` is genuinely useful when a child module needs to reach back out to a sibling of its parent:

```rust
fn deliver_order() {
    println!("order delivered");
}

mod back_of_house {
    pub fn fix_incorrect_order() {
        cook_order();
        super::deliver_order();   // reach up to the parent module
    }

    fn cook_order() {
        println!("cooking");
    }
}
```

`fix_incorrect_order` lives in `back_of_house`, and `deliver_order` lives in the parent (the crate root). `super::deliver_order()` walks up one level to find it. Without `super`, the compiler would look for `deliver_order` inside `back_of_house` and not find it.

## use: bringing names into scope

Writing `front_of_house::hosting::add_to_waitlist()` every time is tedious. The `use` keyword brings a path into the current scope so you can refer to it by a shorter name:

```rust
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("added to waitlist");
        }
    }
}

use crate::front_of_house::hosting;

fn main() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}
```

```
added to waitlist
added to waitlist
```

After `use crate::front_of_house::hosting;`, the name `hosting` is available directly, so the calls shorten to `hosting::add_to_waitlist()`. Every `use std::io;` you've written since chapter 1 was doing exactly this: pulling `io` from the standard library's module tree into scope so you could write `io::stdin()` instead of `std::io::stdin()`.

> **Best practice**
>
> The convention is to `use` the *parent module* of a function (`use ...::hosting;`, then call `hosting::add_to_waitlist()`), so the call site still shows which module the function came from. For types, structs, and enums, the convention is the opposite: bring the type itself into scope (`use std::collections::HashMap;`, then write `HashMap`). It's a small style rule, and rust-analyzer will add `use` lines for you, but following it keeps call sites readable.

## Renaming with as

When two paths would bring in the same name, or a name is just too long, `as` gives it a local alias, the same `as` keyword you'd otherwise meet for casts (lesson [4.10](https://learnrust.net/chapter-4/numeric-conversions/)) but a completely separate use:

```rust
use std::fmt::Result;
use std::io::Result as IoResult;
```

Now `Result` means the formatting one and `IoResult` means the I/O one, so the two collide no longer. You can also combine related imports on one line with braces, `use std::io::{self, Write};`, and re-export a name you've brought in with `pub use` so callers of *your* module can use it too (a technique lesson [13.5](https://learnrust.net/chapter-13/binary-and-library-crates/) leans on).

## Quiz time

**Question #1**

Given this tree, write both an absolute and a relative path to call `seat_party` from `main` (assume the items are `pub`):

```rust
mod front_of_house {
    pub mod hosting {
        pub fn seat_party() {}
    }
}
```

<details class="solution">
<summary>Show solution</summary>

Absolute (from the crate root): `crate::front_of_house::hosting::seat_party();`. Relative (from `main`, which is at the crate root): `front_of_house::hosting::seat_party();`. Both name the same function by walking the same tree from different starting points.

</details>

**Question #2**

What do `super::` and `crate::` each mean at the start of a path?

<details class="solution">
<summary>Show solution</summary>

`crate::` starts an absolute path from the crate root (the top of the module tree). `super::` starts a relative path from the *parent* of the current module, like `..` in a file path. `self::` (the third) starts from the current module.

</details>

**Question #3**

Rewrite this so the call site is shorter, using `use`, while keeping the module name visible at the call (per the best-practice convention):

```rust
fn main() {
    crate::utils::math::square(4);
}
```

<details class="solution">
<summary>Show solution</summary>

```rust
use crate::utils::math;

fn main() {
    math::square(4);
}
```

Bring in the parent module `math`, then call `math::square(4)`. The call still shows that `square` comes from `math`, which is why the convention imports the parent rather than the function itself.

</details>

You've now seen `pub` sprinkled through every example without explanation. The next lesson makes it the main event: visibility, why private-by-default is the right default, and how `pub` builds the boundaries that let a module hide its internals.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
