Modules and Visibility

pub(crate)

The pub(crate) visibility modifier makes an item, struct field, or method visible everywhere inside the current crate (across all sibling, parent, and child modules) while keeping it completely private to external crates that depend on the library.

Comparing pub, pub(crate), and Private Visibility

Visibility Accessible in Same Module & Descendants? Accessible in Sibling / Parent Modules of Same Crate? Accessible to External Crates (cargo doc / SemVer API)?
(private) Yes No No
pub(crate) Yes Yes No
pub Yes Yes Yes (if reachable through a chain of pub modules/re-exports)
Crate Boundary with `pub(crate)`:

  +-------------------------- Current Crate (my_lib) --------------------------+
  |                                                                            |
  |  mod parser {                        mod engine {                          |
  |      pub(crate) fn tokenize() {} ──────> parser::tokenize()  [ALLOWED]     |
  |  }                                   }                                     |
  |                                                                            |
  +----------------------------------------------------------------------------+
                                         │
                                         X  (Blocked at crate boundary!)
                                         v
                              External Crate (consumer)

Sharing Internal Helpers Across Modules with pub(crate)

In a multi-module crate, helper functions, internal error representations, and struct fields often need to be shared between sibling modules (mod storage and mod query) without becoming part of the library's public SemVer contract:

mod codec {
    // Visible to every module in this crate, but never exported to outside crates:
    pub(crate) struct RawHeader {
        pub(crate) magic: u16,
        pub(crate) version: u8,
    }

    pub(crate) fn decode_header(bytes: [u8; 3]) -> RawHeader {
        RawHeader {
            magic: u16::from_be_bytes([bytes[0], bytes[1]]),
            version: bytes[2],
        }
    }
}

mod validator {
    // Sibling module `validator` can freely access `codec::RawHeader` and `decode_header`:
    pub fn is_supported_frame(bytes: [u8; 3]) -> bool {
        let hdr = crate::codec::decode_header(bytes);
        hdr.magic == 0xCAFE && hdr.version == 1
    }
}

fn main() {
    let valid_frame = [0xCA, 0xFE, 0x01];
    let bad_frame = [0x00, 0x00, 0x01];

    println!("valid_frame supported: {}", validator::is_supported_frame(valid_frame));
    println!("bad_frame supported:   {}", validator::is_supported_frame(bad_frame));
}
valid_frame supported: true
bad_frame supported:   false

Using pub(crate) Fields on Public Structs

When a pub struct is part of your public API, marking its internal fields pub(crate) allows other modules inside your crate to construct or inspect the struct directly while still forcing external library users to go through public constructors and methods:

pub mod account {
    #[derive(Debug)]
    pub struct ApiToken {
        pub(crate) raw_key: String, // Crate-internal modules can read `token.raw_key`
    }

    impl ApiToken {
        pub fn new(raw_key: &str) -> Self {
            Self {
                raw_key: String::from(raw_key),
            }
        }
    }
}

mod auth_middleware {
    pub fn verify(token: &crate::account::ApiToken) -> bool {
        // Allowed because `auth_middleware` is in the same crate:
        token.raw_key.starts_with("sk_live_")
    }
}

fn main() {
    let tok = account::ApiToken::new("sk_live_9001");
    println!("Token verified: {}", auth_middleware::verify(&tok));
}
Token verified: true