Visibility & Privacy
Items are private by default. pub exposes across crates; restricted forms limit scope.
Recipe
pub struct Api {
pub version: u32,
secret: String,
}
impl Api {
pub fn new(secret: String) -> Self {
Self { version: 1, secret }
}
}When to reach for this: Encapsulating invariants - fields private, constructors controlled.
Working Example
mod internal {
pub(crate) fn helper() {}
pub(super) fn parent_only() {}
}
pub fn public_api() {
internal::helper();
}What this demonstrates:
pub(crate)visible entire cratepub(super)parent module only- Private by default inside module
Deep Dive
pub(in path) custom path visibility (Rust 2018+). Struct private fields with public type ok if in same crate patterns differ for consumers.
Gotchas
- pub struct private fields - External crate cannot construct without pub fn. Fix: Constructor.
- pub use reexport confusion - Hides actual path. Fix: Document prelude.
- Too pub - Leaks internals. Fix:
pub(crate)default internal APIs. - Test modules need pub - Or
#[cfg(test)]in same module. - macro exported privacy -
#[macro_export]is public crate root.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
pub(crate) | Internal API | Needs external use |
#[doc(hidden)] | Hide docs but public | True privacy needed |
sealed trait module | Limit impls | Open trait |
FAQs
pub(crate) vs pub?
Crate-wide vs world.pub(super)?
Parent module visibility.pub(in self::a)?
Path restricted.private module?
mod foo; not pub - child items can still be pub use.ffi pub?
extern need pub symbols.test visibility?
same module tests private.wasm export?
wasm_bindgen pub fns.lint missing_docs?
On pub items.semver?
pub API is stable contract.encapsulation?
methods not fields.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.