---
title: "13.3 Visibility: pub"
description: "Items are private by default; pub exposes them, pub(crate) limits exposure to the crate, and struct fields are made public one at a time, which is encapsulation."
url: "https://learnrust.net/chapter-13/visibility-pub/"
last_updated: "2026-06-13"
---

# 13.3 Visibility: pub

The previous lesson marked things `pub` and asked you to take it on faith. Now the faith is repaid. **Visibility** is the rule about what code can see what, and it's how modules stop being mere folders and become real boundaries: a module can hide its inner workings and expose only a deliberate, public surface. This is **encapsulation**, one of the most important ideas in structuring software, and Rust builds it from a single keyword.

## Private by default

In Rust, everything is private to its module unless you say otherwise. A child module's items are hidden from the code outside it:

```rust
mod kitchen {
    fn secret_recipe() {
        println!("a pinch of salt");
    }
}

fn main() {
    kitchen::secret_recipe();
}
```

```
error[E0603]: function `secret_recipe` is private
 --> src/main.rs:8:14
  |
8 |     kitchen::secret_recipe();
  |              ^^^^^^^^^^^^^ private function
  |
note: the function `secret_recipe` is defined here
 --> src/main.rs:2:5
  |
2 |     fn secret_recipe() {
  |     ^^^^^^^^^^^^^^^^^^
```

`secret_recipe` exists, the path is correct, but the function is private to `kitchen`, so `main` can't call it (E0603). This is the opposite of many languages, where things are public unless hidden, and the default is deliberate: code is private until you make a conscious decision to expose it, so a module's public surface is always something you chose, never something that leaked out by accident.

> **Key insight**
>
> Private-by-default flips the burden in your favor. Instead of remembering to hide every internal helper (and paying for the one you forget), you expose only what you mean to. Everything you don't mention stays an implementation detail you're free to change later without breaking anyone, because no one outside could depend on it. The public surface is a promise; private-by-default keeps you from making promises by accident.

## pub exposes an item

Add `pub` and the item becomes visible to the parent module (and, transitively, wherever the parent can reach):

```rust
mod kitchen {
    pub fn order_food() {
        let dish = prepare();        // private helper, callable from inside
        println!("serving {dish}");
    }

    fn prepare() -> &'static str {
        "soup"
    }
}

fn main() {
    kitchen::order_food();           // public: allowed
}
```

```
serving soup
```

`order_food` is `pub`, so `main` can call it. `prepare` is private, so `main` cannot, but `order_food` can, because it lives *inside* `kitchen` and private items are visible within their own module. This is the encapsulation pattern in miniature: `kitchen` exposes *what you can do* (`order_food`) and hides *how it does it* (`prepare`). You could rewrite `prepare` entirely, and as long as `order_food`'s behavior is unchanged, no caller notices.

One subtlety worth stating: making a module `pub` only makes the module itself reachable. The items inside it are still private unless *they* are also `pub`. Exposure is per-item, all the way down, which is why lesson [13.2](https://learnrust.net/chapter-13/defining-modules/)'s examples needed `pub` on both the module and its functions.

## pub(crate): public within, private without

Between fully private and fully public sits a useful middle ground. `pub(crate)` makes an item visible everywhere in *your* crate but not to outside code that depends on your crate as a library (lesson [13.5](https://learnrust.net/chapter-13/binary-and-library-crates/)). It's the right choice for things that many of your own modules share but that aren't part of the promise you make to external users:

```rust
mod helpers {
    pub(crate) fn shared_utility() {
        println!("used across the crate");
    }
}
```

Any module in the same crate can call `helpers::shared_utility()`, but if someone adds your crate as a dependency, they can't. There are finer-grained forms (`pub(super)`, `pub(in some::path)`), but `pub`, `pub(crate)`, and private cover almost everything you'll write.

## Struct fields are public one at a time

`pub` on a struct (lesson [10.2](https://learnrust.net/chapter-10/defining-and-instantiating-structs/)) exposes the *type*, but its fields stay private unless each is individually marked `pub`. This is the mechanism behind real encapsulation of data:

```rust
mod bank {
    pub struct Account {
        pub owner: String,
        balance: u64,           // private: only `bank` can touch it
    }

    impl Account {
        pub fn new(owner: String) -> Account {
            Account { owner, balance: 0 }
        }

        pub fn deposit(&mut self, amount: u64) {
            self.balance += amount;
        }

        pub fn balance(&self) -> u64 {
            self.balance
        }
    }
}

fn main() {
    let mut acct = bank::Account::new(String::from("Ada"));
    acct.deposit(100);
    println!("{} has {}", acct.owner, acct.balance());
    // acct.balance = 999;   // refused: balance is private
}
```

```
Ada has 100
```

`owner` is `pub`, so `main` reads it directly. `balance` is private, so `main` cannot set it to a bogus value; the only way to change it is through `deposit`, which `bank` controls. This is exactly the field-protection lesson [10.2](https://learnrust.net/chapter-10/defining-and-instantiating-structs/) promised modules would provide. The struct enforces its own rules because outside code physically cannot reach past its methods. (Note that `new` must be `pub` and is necessary precisely *because* `balance` is private: outside code can't write the struct literal directly when a field is hidden, so it depends on the constructor.)

> **Best practice**
>
> Keep struct fields private and expose behavior through methods, unless the struct is a plain data bundle with no rules to enforce (like a `Point` whose fields are just coordinates). Private fields let you change a type's internal representation later, validate on every change, and maintain invariants. This is the same instinct as private-by-default modules: expose a deliberate surface, hide the rest.

## Quiz time

**Question #1**

What's the default visibility of an item in a module, and why is that a good default?

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

Private to its module. It's a good default because it makes the public surface something you opt into deliberately: nothing leaks out by accident, and anything you don't mark `pub` stays an internal detail you can change freely without breaking callers.

</details>

**Question #2**

This is refused. Why, and what's the fix?

```rust
mod shapes {
    pub struct Circle {
        radius: f64,
    }
}

fn main() {
    let c = shapes::Circle { radius: 2.0 };
}
```

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

`Circle` is `pub`, but its field `radius` is private, so `main` can't build the struct literal with that field (it would be an E0451-style privacy error on the field). Fixes: mark the field `pub radius: f64`, or (better, for encapsulation) keep it private and add a `pub fn new(radius: f64) -> Circle` associated function inside `shapes` for outside code to call.

</details>

**Question #3**

When would you choose `pub(crate)` over `pub`?

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

When an item should be shared across your own crate's modules but should *not* be part of the public API that external code (depending on your crate as a library) can use. `pub(crate)` is visible everywhere inside your crate and invisible outside it, which is ideal for internal helpers that several of your modules need but that you don't want to promise to the outside world.

</details>

You can now organize code into modules with controlled visibility, all within one file. The next lesson does the thing every growing program needs: moves those modules into separate files. It's the lesson that replaces an entire C++ chapter, and it's shorter than this one.

## Sitemap

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