More than one program in a project
Soon you’ll want a second program next to your main one: a seed script, a migration tool, a small demo. Cargo lets one project hold as many as you like.
RememberEvery .rs file directly in src/bin/ (or src/bin/<name>/main.rs) is its own program with its own main. Shared code goes in src/lib.rs.
Here’s the layout. Each program has its own main, and they all share the code in lib.rs:
tools/ ├── examples/ │ └── demo.rs example "demo" ├── src/ │ ├── bin/ │ │ └── seed.rs program "seed" │ ├── lib.rs shared code, used as tools::... │ └── main.rs program "tools" ├── Cargo.lock created by Cargo └── Cargo.toml
// Shared code. Every program in this package can use it as `tools::...`.pub fn banner(program: &str) -> String { format!("== {program} ==")}// The main program: run with `cargo run --bin tools`.fn main() { println!("{}", tools::banner("server")); println!("serving requests...");}// A second program: run with `cargo run --bin seed`.fn main() { println!("{}", tools::banner("seed")); println!("inserted 3 sample rows");}// An example for people reading your code: run with `cargo run --example demo`.fn main() { println!("{}", tools::banner("demo"));}== seed == inserted 3 sample rows$ cargo run --bin tools
== server == serving requests...$ cargo run --example demo
== demo ==
src/main.rsis the program named after the package, heretools.src/bin/seed.rsis a program calledseed. Add as many files there as you need. A bigger one can be a folder,src/bin/seed/main.rs, with its own modules (Try it #1).examples/holds programs that show how to use your code.cargo buildandcargo rundon’t build them, so they suit demos.cargo testdoes compile them, to check they still build (Try it #3).src/lib.rsmakes the package a library too. Every program in the package can use it by the package name, liketools::banner. The Go version below puts the same code in a package,internal/banner.
For how files, crates and mod fit together, see Files and modules and the Modules lesson.
The same layout in Go
Section titled “The same layout in Go”module example.com/tools
go 1.27package main
import ( "fmt"
"example.com/tools/internal/banner")
func main() { fmt.Println(banner.For("seed")) fmt.Println("inserted 3 sample rows")}package main
import ( "fmt"
"example.com/tools/internal/banner")
func main() { fmt.Println(banner.For("server")) fmt.Println("serving requests...")}package banner
import "fmt"
// Shared code for every program in this module.func For(program string) string { return fmt.Sprintf("== %s ==", program) }== seed == inserted 3 sample rows$ go run ./cmd/server
== server == serving requests...
Where extra programs live in other languages
Section titled “Where extra programs live in other languages”| Language | Where extra programs live | Run one |
|---|---|---|
| Rust | src/bin/seed.rs (each with main), examples/demo.rs |
cargo run --bin seed, cargo run --example demo |
| Go | a folder with package main; cmd/seed/ is the usual place |
go run ./cmd/seed |
| Python | any file; the if __name__ == "__main__": guard stops import seed from running it |
python3 seed.py |
| TypeScript | any .ts file |
node seed.ts (Node 22.18 or newer strips the types; I ran 24) |
| Java | any class with main |
java Seed.java, or javac Seed.java then java Seed |
| Kotlin | any file with fun main |
kotlinc Seed.kt -include-runtime -d seed.jar, then java -jar seed.jar; a Gradle build runs the one mainClass it names |
| C# | a project’s Program.cs; a second program is usually a second project in the solution |
dotnet run --project Seed |
| C and C++ | one source file with main per executable |
gcc seed.c -o seed, g++ seed.cpp -o seed; in CMake, add_executable(seed seed.c) (not run) |
Every command above ran in this course’s image, except CMake, which is not installed there. The C# one ran as dotnet run --no-restore --project Seed from an offline project template, because the image has no network.
Plain cargo run stops working
Nothing in your code changed, but Cargo stops and asks a question.
No direct equivalent in Go.No direct equivalent in Kotlin.Not run in Python on this page.Not run in TypeScript on this page.Not run in Java on this page.Not run in C# on this page.Not run in C on this page.Not run in C++ on this page.[package]name = "tools"version = "0.1.0"edition = "2024"
[dependencies]Go has no default-run either: go run . at the module root has no main package to run, so you name the folder, as in go run ./cmd/seed.
Gradle's run task uses the one mainClass you configured, so you pick it in the build file.
There is no Python version of this one.
There is no TypeScript version of this one.
There is no Java version of this one.
There is no C# version of this one.
There is no C version of this one.
There is no C++ version of this one.
What does the compiler say? Guess first, then open.
error: `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key. available binaries: seed, tools
Go has no default-run either: go run . at the module root has no main package to run, so you name the folder, as in go run ./cmd/seed.
Gradle's run task uses the one mainClass you configured, so you pick it in the build file.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
With one program, cargo run knew what to run. Nothing about your code changed, so this feels like it broke for no reason.
Now there are two programs, tools and seed, and Cargo won't guess which one you meant.
Picking one for you could run the wrong thing, such as a seed script instead of the server. Name the program each time with --bin, or set a default once in Cargo.toml.
The fix
Compiles and runs.
[package]name = "tools"version = "0.1.0"edition = "2024"default-run = "tools"
[dependencies]== server == serving requests...
Try it yourself
Section titled “Try it yourself”Run these in a copy of the project above.
- Make a program a folder. Add
src/bin/report/main.rsandsrc/bin/report/table.rs, withmod table;inmain.rs. Cargo findsreportwith no change toCargo.toml, andmod table;loads the file beside it.
// A program that is a folder: its own modules live next to this file.mod table;
fn main() { println!("{}", tools::banner("report")); table::print(&[("seed", 3), ("report", 1)]);}pub fn print(rows: &[(&str, u32)]) { for (name, n) in rows { println!("{name:<8}{n}"); }}== report == seed 3 report 1
- Mistype a name. Run
cargo run --bin sed. Cargo says there is no such program and suggestsseed.
error: no bin target named `sed` in default-run packages help: a target with a similar name exists: `seed`
- Find out what
cargo buildskips. Runcargo build, thenls target/debug/examples. The folder is empty untilcargo build --example demomakesdemo. Runningcargo testin the same project makesdemoappear there as well.
$ cargo build $ ls target/debug/examples # the hash differs between toolchains, so it is masked $ cargo build --example demo $ ls target/debug/examples # the hash differs between toolchains, so it is masked demo demo-<hash> demo-<hash>.d demo.d
Read more
Section titled “Read more”- Package Layout in the Cargo Book: where
src/bin/,examples/andtests/go, including programs made of several files. - Cargo Targets: binaries, examples, and how to configure each with
[[bin]]and[[example]]. - The
default-runfield: the fix for the gotcha above. - Packages and Crates in the Rust Book: packages, library crates and binary crates.
- Workspaces in the Cargo Book.
Learn Rust is an independent project, not affiliated with the Rust Project or the Rust Foundation. Code and text are under the MIT licence.Source on GitHub.