Organizing code in binary crates

Within a binary crate, here's the organization that's recommended.


fn main() {
//! Contains command parsers and logic.

use clap::Parser;

#[derive(Debug, Parser)]
pub struct MyApp {
    // Options, subcommands etc
    #[clap(short, long, default_value_t)]
    my_arg: usize,

impl MyApp {
    pub fn exec(self) -> color_eyre::Result<()> {
        println!("The value of my-arg is {}", self.my_arg);


fn main() {
//! Help text for my-app.
//! Can contain information about what the binary does, command-line options,
//! configuration, etc.

mod command;
// ... other modules

// This is the only export from the crate. It is marked hidden and
// is not part of the public API.
pub use command::MyApp;


use clap::Parser;
use my_app::MyApp;

fn main() -> color_eyre::Result<()> {

    let my_app = MyApp::parse();


  • Most of the logic is within
    • In general, you should keep as minimal as possible, unless your entire library fits in it. That's because all methods and fields in are visible to the entire library---code in the top-level module cannot be marked private to the rest of the module.
  • There's a separate from the that contains main.
    • There are several advantages to having a In particular, rustdoc doesn't use standard privacy rules if building documentation from, so private modules are visible in the public documentation.
  • Only the top-level MyApp is exported.
    • The top-level MyApp is all should generally need to care about.
  • MyApp is marked #[doc(hidden)].
    • The details of MyApp are only meant to be seen by main. The library is not part of the public API. Only the command-line interface is.
  • src/bin/ instead of src/
    • While src/ works just as well, src/bin makes it harder to accidentally import library code with mod statements.