---
title: How to re-export with pub use
summary: Use pub use to re-export items from internal modules at the crate root, separating your public API from your internal layout. Rename with 'as' and curate what users see.
lang: en
slug: how-to-re-export-with-pub-use
published: 2026-04-17T12:05:42+00:00
updated: 2026-04-25T22:00:13+00:00
canonical: https://www.rustfaq.org/en/how-to-re-export-with-pub-use/
---

# How to re-export with pub use

## When your crate's API doesn't match its filesystem

You've built a Rust library. Internally it has half a dozen modules: `parser`, `tokenizer`, `error`, `config`, all neatly organized by purpose. But when somebody else wants to use your crate, you don't want them writing `my_crate::parser::ast::Node` for every little thing. You want them writing `my_crate::Node`. The internal layout is your problem; the public surface should be clean and small.

That's where `pub use` comes in. It lets the inside of your crate look one way and the outside look another. The mechanism is called re-exporting, and it's one of those features that seems trivial until you realize how much of every well-designed crate quietly depends on it.

## The basic shape

Imagine `src/lib.rs` of a tiny library:

```rust
// An internal module. We mark it `pub` so its items can flow out,
// but we'll re-export the parts we want callers to use directly.
pub mod parser {
    pub struct Ast {
        pub nodes: Vec<String>,
    }

    pub fn parse(input: &str) -> Ast {
        Ast { nodes: input.split_whitespace().map(String::from).collect() }
    }
}

// Re-export the items at the crate root. Now `my_crate::Ast` and
// `my_crate::parse` work, even though they're really inside `parser`.
pub use parser::{Ast, parse};
```

A user of your crate will write:

```rust
use my_crate::{Ast, parse};

fn main() {
    let tree = parse("hello world");
    println!("{} nodes", tree.nodes.len());
}
```

They never have to know that `parser` exists. If you reorganize and rename `parser` to `frontend` next month, you only have to update the `pub use` line and your users' code keeps working unchanged.

## Why "pub use" instead of "use"

Plain `use` is just a shortcut. It brings a name into scope for the current module. `pub use` does the same thing, but also makes the imported name part of that module's public API.

```rust
mod inner {
    pub fn ping() {}
}

// Plain `use`: `ping` is visible inside this file but not exported.
use inner::ping;

// pub use: `ping` is now reachable from outside the crate as `crate::ping`.
pub use inner::ping;
```

If you forget the `pub`, your users get errors like:

```text
error[E0603]: function `ping` is private
```

The fix is just to add `pub` in front.

## What it really gives you

Three things you should know about.

**Decoupling layout from API.** Your file structure can mirror your internal architecture (one file per concept, neat sub-folders). Your public API is whatever you `pub use` at the crate root. They never have to match.

**Stable interfaces over time.** When you refactor, the path on the inside changes. The path on the outside doesn't, as long as you keep the re-export pointing at the new location. Your users see no breakage.

**Curating the surface.** Big crates often have many internal types that exist for implementation reasons but aren't meant to be used directly. `pub use` lets you elevate the handful of things that should be the front door, leaving the rest reachable but not advertised.

The serde crate is a famous example: nearly its entire user-facing API is re-exports from internal modules, presented through a flat top-level namespace.

## Re-exporting from a sub-module

`pub use` isn't limited to `lib.rs`. You can use it inside any module to flatten the view of that module's children.

```rust
// src/lib.rs
pub mod io {
    pub mod reader;
    pub mod writer;

    // Re-export at the io module level. Now users of `my_crate::io`
    // get `Reader` and `Writer` directly without typing the inner module names.
    pub use reader::Reader;
    pub use writer::Writer;
}
```

A user does:

```rust
use my_crate::io::{Reader, Writer};
```

without knowing or caring that there's a `reader` submodule inside `io`. The standard library uses this pattern heavily. `std::io::Result` is actually `std::io::Result`, but defined inside a submodule and re-exported.

## Renaming on the way out

Sometimes the internal name and the public name should differ. Maybe `internal::FooImpl` is fine inside but you want to expose it as just `Foo`. Use `as`:

```rust
pub use internal::FooImpl as Foo;
```

This is also handy for resolving conflicts when two re-exports would collide:

```rust
pub use crate::v1::Client as ClientV1;
pub use crate::v2::Client as ClientV2;
```

## A more realistic example: a small library facade

Here's a layout that's typical for a published crate:

```rust
// src/lib.rs

// Internal modules. Each holds its own types and functions.
mod config;
mod connection;
mod error;
mod query;

// The public façade. Everything users should see lives at the root.
pub use config::Config;
pub use connection::Connection;
pub use error::{Error, Result};
pub use query::{Query, QueryBuilder};

// Hidden but documented escape hatches: exposed for power users
// who want the full path. The leading underscore module stays public.
pub mod internal {
    pub use crate::connection::raw_socket;
}
```

Notice three things. The internal modules are declared `mod`, not `pub mod`: their items are reached only through the re-exports. The `Result` type is re-exported alongside `Error`, which is a common pattern (so callers can write `my_crate::Result<T>` instead of `std::result::Result<T, my_crate::Error>`). And the `internal` module is a deliberate "I see you, power users" escape hatch for things that aren't part of the curated façade but shouldn't be impossible to reach.

That last pattern is worth copying. Re-export the things 95% of users want at the crate root, but leave a `mod internal` or `mod raw` for the people who need to break the abstraction.

## Common pitfalls

You forgot `pub` in front of `use`:

```text
error[E0603]: function `helper` is private
```

Fix: change `use` to `pub use`.

You re-exported a type that depends on private types. The compiler will complain that you're "leaking a private type in a public interface" (E0446):

```text
error[E0446]: private type `Internal` in public interface
```

Fix: either make the private type public, or stop re-exporting the type that depends on it.

Your module isn't even reachable. If `lib.rs` has `mod parser;` (without `pub`), the items inside aren't accessible outside the crate. `pub use parser::Foo` is fine because `pub use` looks inside even non-`pub` modules. But `parser::Foo` directly from outside won't work. This is exactly the trick: `mod parser;` keeps the module private, `pub use parser::Foo;` exposes only what you choose.

You re-exported a glob (`pub use submodule::*`) and accidentally exposed things you didn't mean to. Glob re-exports are convenient but dangerous: if you add a new public item to the inner module later, it's automatically part of your public API. Prefer explicit lists for stability.

You re-exported across crates. Yes, you can `pub use other_crate::Thing;` and your downstream users will see `your_crate::Thing`. Useful for prelude-style crates, but be aware: bumping `other_crate`'s major version is now a breaking change for your users too.

## When to use what

Reach for `pub use` whenever the thing you want users to type doesn't match where the item naturally lives in your code. That's most of the time, in any project bigger than a single-file crate.

Don't reach for it for everything. If your crate is tiny, just put items at the root. Re-exports cost nothing at runtime but add a layer of indirection in the docs and source that only pays off when you have something to flatten.

For internal modules used only by your own code, plain `use` is enough. Save `pub use` for what should be visible to the outside world.

## Where to go next

Module organization in Rust is a topic with surprising depth, and `pub use` is one of the more useful tools in the toolbox.

[How to Organize a Large Rust Project into Modules](/en/how-to-organize-a-large-rust-project-into-modules/)

[What Is a Crate Root (lib.rs vs main.rs)?](/en/what-is-a-crate-root-librs-vs-mainrs/)

[How to Split a Crate into Multiple Files](/en/how-to-split-a-crate-into-multiple-files/)
