File types · Explainer

The Rust source file (.rs)

An RS file is a plain-text file of source code in the Rust programming language, which a compiler turns into a standalone program or a library. This guide explains what's inside one, how to compile, run and test it with rustc and Cargo, which edition it's written for, and has free sample Rust files to download for testing.

At a glance

Full name
Rust source file
Extensions
.rs
MIME type
None registered; Linux desktops use text/rust
Kind
Plain text (source code), compiled to machine code before it runs
Encoding
UTF-8, required by the language; a leading byte order mark is ignored
Language owner
The Rust Project; the language is described by The Rust Reference
First released
Rust 1.0 on 15 May 2015, developed with Mozilla's sponsorship
Editions
2015, 2018, 2021 and 2024 (stable since Rust 1.85, February 2025)
Tools
rustc compiles; Cargo builds, tests and fetches dependencies; rustup installs both
Comments
// line, /* block */ (they nest), /// and //! for documentation
Magic number
None; a #! line is allowed at the very start

The basics

What is an RS file?

An .rs file holds Rust source code: text that a programmer writes and the Rust compiler translates into machine code. The result is a native program (an .exe on Windows, a binary with no extension on macOS and Linux) or a library that other Rust code uses. You can open the file in any text editor and read it, but you can't run it directly.

Rust is used where speed and reliability both matter: command-line tools, web servers, browsers, operating system components and code compiled to WebAssembly. Its compiler checks at compile time that memory is used safely, without a garbage collector, which is why Rust code often takes longer to get compiling and then has fewer crashes.

Three things that explain a lot of confusion:

  • A crate is the unit of compilation, not a file. The compiler starts from one root file (usually src/main.rs or src/lib.rs) and pulls in the other .rs files that the root declares with mod. A .rs file that nothing declares is silently ignored.
  • Most projects are built with Cargo, not by calling the compiler. Cargo reads Cargo.toml, downloads dependencies from crates.io and runs rustc with the right options.
  • The edition changes how a file is read. The same code can compile under one edition and fail under another. It's set in Cargo.toml, not in the .rs file, so a single file on its own doesn't say which one it needs.

Anatomy

What's inside a Rust file

A Rust file is a list of items: use declarations, types, functions, modules and constants, in any order. Statements only appear inside functions. Here is a small but complete program that converts a temperature, with a unit test at the bottom, part by part.

src/main.rs
//! A tiny temperature converter.
use std::env;

#[derive(Debug)]
struct Reading {
    celsius: f64,
}

impl Reading {
    fn fahrenheit(&self) -> f64 {
        self.celsius * 9.0 / 5.0 + 32.0
    }
}

fn parse(arg: &str) -> Result<Reading, String> {
    let celsius: f64 = arg.parse().map_err(|_| format!("not a number: {arg}"))?;
    Ok(Reading { celsius })
}

fn main() {
    let arg = env::args().nth(1).unwrap_or_else(|| String::from("20"));
    match parse(&arg) {
        Ok(r) => println!("{}°C is {:.1}°F", r.celsius, r.fahrenheit()),
        Err(e) => eprintln!("error: {e}"),
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn boiling() {
        assert_eq!(super::parse("100").unwrap().fahrenheit(), 212.0);
    }
}
  1. 1//! A tiny temperature converter.

    A documentation comment

    //! documents the file or crate it's in; /// documents the item below it. cargo doc turns both into HTML pages. Ordinary comments use // or /* … */.

  2. 2use std::env;

    A use declaration

    Brings a module from the standard library (std) into scope, so the code can write env::args() instead of the full path.

  3. 3#[derive(Debug)]

    An attribute

    #[…] attaches information to the next item. derive asks the compiler to write a trait implementation, here the one that lets {:?} print the struct.

  4. 4struct Reading { celsius: f64 }

    A struct

    A type with named fields. Rust has no classes: data lives in structs and enums, behaviour in impl blocks and traits.

  5. 5impl Reading { fn fahrenheit(&self) … }

    A method

    &self means the method borrows the value instead of taking ownership of it. The last expression without a semicolon is the return value.

  6. 6-> Result<Reading, String>

    A Result

    Rust has no exceptions for ordinary errors. A function that can fail returns Ok(value) or Err(error), and the caller has to deal with both.

  7. 7map_err(…)?

    The ? operator

    If the parse failed, ? returns the error from parse straight away; otherwise it unwraps the value. format! builds a String, and {arg} inserts the variable.

  8. 8fn main()

    The entry point

    Where the program starts. A crate whose root file has fn main compiles to an executable; a library's root, lib.rs, has none.

  9. 9match parse(&arg) { Ok(r) => …, Err(e) => … }

    A match

    Picks a branch by the shape of the value. The compiler refuses a match that doesn't cover every case.

  10. 10println!(…) / eprintln!(…)

    Macros

    The ! marks a macro, code that expands at compile time. These print to standard output and standard error; the format string is checked when the program is compiled.

  11. 11#[cfg(test)] mod tests { #[test] … }

    A unit test

    Compiled only by cargo test or rustc --test, so it adds nothing to the normal program. Tests live in the same file as the code they test.

How to

How to compile and run a .rs file

Install Rust with rustup from the official website; it installs rustc, Cargo, rustfmt and Clippy, and rustup update keeps them current. The compiler also needs a linker: on Windows the installer asks you to install Visual Studio's build tools, on macOS run xcode-select --install, and on Linux install GCC or Clang (on Ubuntu, build-essential).

rustccargo
Compile one filerustc --edition 2024 main.rsNeeds a package: cargo new demo, then put the code in src/main.rs
Run it./main (macOS, Linux) or main.exe (Windows)cargo run builds and runs in one step
Optimised buildrustc -O main.rscargo build --release, output in target/release/
Default edition2015, unless you pass --editionWhatever Cargo.toml says; cargo new writes the newest
Dependencies from crates.ioNot handledListed in Cargo.toml, downloaded and built for you
Check without buildingNo equivalentcargo check type-checks fast without producing a program

The edition trap

Run rustc file.rs without --edition and the file is compiled as Rust 2015. Modern code can then fail with errors like expected identifier, found keyword or async fn is not permitted in Rust 2015. Pass --edition 2024, or build with Cargo.

There's no interpreter: every change means compiling again, though cargo run only recompiles what changed. The compiled program runs on its own, without Rust installed, on the operating system and processor it was built for.

Projects

Cargo.toml, main.rs, lib.rs and mod.rs

A Cargo package is a folder with a Cargo.toml manifest at the top and the .rs files under src/. Cargo finds targets by file name, so the layout is a convention you rarely configure:

converter/ (a Cargo package)
converter/
├── Cargo.toml        the manifest: name, edition, dependencies
├── Cargo.lock        exact dependency versions (written by Cargo)
├── src/
│   ├── main.rs       the program's entry point (fn main)
│   ├── lib.rs        a library crate, if the package has one
│   ├── units.rs      module "units", declared with: mod units;
│   └── bin/
│       └── extra.rs  a second executable
├── tests/            integration tests
├── examples/         example programs (cargo run --example name)
└── target/           build output, not committed to version control
Cargo.toml
[package]
name = "converter"
version = "0.1.0"
edition = "2024"

[dependencies]
serde = { version = "1", features = ["derive"] }
  • src/main.rs is the root of the executable, src/lib.rs the root of a library crate. A package can have both: putting the logic in lib.rs and keeping main.rs thin makes it testable from tests/.
  • Modules map to files. mod units; in main.rs makes the compiler look for src/units.rs, or the older src/units/mod.rs. Having both is a compile error. Submodules of units go in a src/units/ folder.
  • File and crate names: use lowercase with underscores (order_items.rs), because a module name must be a valid identifier. Package names may use hyphens; in code, my-tool becomes my_tool.
  • Cargo.lock records the exact versions of every dependency. Commit it for programs, so every build uses the same code.
  • build.rs at the package root is a build script: Cargo compiles and runs it before building the package.

Versions

Rust editions: 2015, 2018, 2021 and 2024

Rust ships a new compiler version every six weeks, and every version compiles all editions. An edition is an opt-in set of changes that wouldn't be backwards compatible, such as new keywords. Crates of different editions work together: a 2024 program can depend on a 2015 library.

EditionStable sinceNotable changes
2015Rust 1.0 (May 2015)The original language. Still the default when no edition is given.
2018Rust 1.31New module paths (crate::, no extern crate), dyn Trait, async and await become keywords, foo.rs next to a foo/ folder instead of mod.rs
2021Rust 1.56Closures capture individual fields, array.into_iter() yields values, TryFrom and TryInto in the prelude, consistent panic! formatting
2024Rust 1.85 (February 2025)gen reserved as a keyword, unsafe extern blocks, new temporary scopes for if let and tail expressions, a Rust-version-aware dependency resolver, a new rustfmt style edition

To move a package to a newer edition, run cargo fix --edition, change edition in Cargo.toml, then build, test and run cargo fmt. cargo fix handles most changes; macros and doc tests sometimes need editing by hand.

Library features are tied to the compiler version, not the edition. A method added in Rust 1.87, such as u32::is_multiple_of, doesn't exist on 1.86 whatever the edition. Cargo's rust-version field states the oldest compiler a package supports.

Tooling

cargo fmt, cargo clippy and cargo test

CommandWhat it does
cargo fmtReformats every .rs file in the package in the community style (4-space indents, a 100-column limit) with rustfmt. cargo fmt --check only reports differences, which is what CI usually runs. Settings go in rustfmt.toml.
cargo clippyRuns Clippy, a collection of several hundred lints for likely bugs, slow code and unidiomatic style. cargo clippy -- -D warnings turns every warning into an error.
cargo testBuilds the package in test mode and runs unit tests (#[test] functions inside #[cfg(test)] modules), integration tests in tests/ and the code examples in /// documentation comments.
cargo checkType-checks without generating machine code. Much faster than a build, so editors run it constantly.
cargo doc --openBuilds HTML documentation from the doc comments and opens it.

Without Cargo, rustc --edition 2024 --test file.rs builds a test runner for a single file: run the program it produces and it prints one line per test. Doc tests need Cargo, because their examples are compiled against the library as if they were outside code.

Related formats

The files around a .rs file, and how Rust compares

FileWhat it is
.rsRust source code, plain text.
Cargo.tomlThe package manifest, in TOML: name, edition, dependencies, build settings.
Cargo.lockExact versions and checksums of every dependency, written by Cargo.
rust-toolchain.tomlPins the compiler version or channel (stable, nightly) for a project; rustup reads it.
.rlibA compiled Rust library, an intermediate file in target/. Not portable between compiler versions.
An executableThe compiled program: name.exe on Windows, name on macOS and Linux. Runs without Rust installed.
.wasmWebAssembly. Rust compiles to it for browsers and other WebAssembly runtimes.
Rust (.rs)C++ (.cpp)Go (.go)
Compiled toNative machine codeNative machine codeNative machine code
Memory managementOwnership and borrowing, checked at compile timeManual or smart pointersGarbage collector
Build tool and packagesCargo and crates.io, built inSeveral (CMake, vcpkg, Conan…)The go command and modules, built in
Header filesNone.h, .hppNone
Official formatterrustfmtNone (clang-format is common)gofmt

Troubleshooting

The Rust compile errors people hit most

Every Rust error has a code; rustc --explain E0382 prints a full explanation with examples.

ErrorUsual causeFix
E0382: borrow of moved valueA String, Vec or other owned value was passed by value, so it moved, then used againPass a reference (&value), or .clone() it if you need two copies
E0502: cannot borrow as mutable because it is also borrowed as immutableA reference into a collection is still in use while the collection is changedFinish using the reference first, or copy the value out
E0308: mismatched typesA value of one type where another is expected, such as "5" for an i32Convert explicitly: "5".parse::<i32>()
expected identifier, found keyword asyncModern code compiled as Rust 2015 by a bare rustc callrustc --edition 2024, or build with Cargo
E0432: unresolved import / can't find crateA crate from crates.io used without Cargo, or not listed in Cargo.tomlcargo add name, then build with Cargo
E0583: file not found for modulemod name; with no name.rs or name/mod.rs next to the fileCreate the file, or fix the module name
linker cc not found (or link.exe on Windows)No C linker installedInstall build-essential, the Xcode command-line tools or Visual Studio's C++ build tools

sample-compile-error.rs below reproduces E0382 and E0502 on purpose, with the fix for each in a comment.

How to

How to open and edit a .rs file, and is it safe?

  • Read it: any text editor shows it: Notepad, TextEdit (in plain-text mode), or a browser if it's online. Rust files are always UTF-8.
  • Edit it: VS Code with the rust-analyzer extension gives completion, inline errors and go-to-definition; RustRover, Zed, Neovim and Helix also support Rust. rust-analyzer needs the file to be part of a Cargo package to understand it fully.
  • Phones and tablets: you can read .rs files in any text or code viewer, but compiling needs a computer, or an online playground such as play.rust-lang.org.

Opening a .rs file in an editor is safe: it's text, and nothing runs. Building a project you don't trust is another matter:

  • Build scripts and procedural macros run code on your computer. cargo build compiles and runs a package's build.rs and the procedural macros of every dependency, with your user's permissions. Reading the code first, or building in a container or virtual machine, is the safe way to try an unknown project.
  • Dependencies are other people's code. Check the names of crates you add: look-alike names (typosquatting) are a known way to slip in malicious packages. Tools such as cargo audit check Cargo.lock against a database of security advisories.
  • unsafe doesn't mean dangerous to open. It marks blocks where the programmer, not the compiler, guarantees memory safety. Reviewers look at those blocks first.

Free downloads

Sample Rust files to download

Free sample Rust files for testing compilers, editors, CI pipelines, syntax highlighters, upload filters and size limits. Every sample except the deliberately broken one compiles with Rust 1.97 and passes cargo fmt --check and cargo clippy -- -D warnings in a 2024-edition package.

sample-main.rs · 5.9 KBDownloadOpen
Loading…

What's inside sample-main.rs

The file is commented: open it in a text editor and each numbered comment marks one of these parts. Compile it with rustc --edition 2024 sample-main.rs and run the result: it prints a total per person, and reports one line it skipped.

  1. Comments 1 to 4: types

    A use declaration, a struct and an enum with #[derive], and an impl block whose match turns a text label into an enum value.

  2. Comment 5: an error type

    An enum of the ways parsing can fail, and a Display implementation that turns each into a readable message.

  3. Comments 6 and 7: Result, ? and Option

    parse_line returns a Result and uses let … else and ?; parse_cents returns an Option and keeps money in whole cents with overflow-checked arithmetic.

  4. Comments 8 and 9: borrowing and iterators

    A function that borrows the list and returns a BTreeMap whose keys borrow from it, then filter, map and sum on an iterator.

  5. Comments 10 and 11: data and main

    The input is a string constant with five lines, one of them invalid. main collects the good lines, prints the bad one to standard error with eprintln!, and prints totals: €49.75 for Ada Example, €138.90 for Ben Example.

  6. Comment 12: unit tests

    Three #[test] functions in a #[cfg(test)] module. rustc --edition 2024 --test sample-main.rs -o sample-tests builds a test runner; running it reports 3 passed.

All sample Rust files

  • Commented sample program

    sample-main.rs · 5.9 KB (6,059 bytes)

    A complete command-line program: structs, enums, traits, Result and ?, borrowing, iterators and a unit-test module, with numbered comments explaining each part. Compiles with rustc alone, no dependencies.

    • Checking a compiler, CI job or syntax highlighter on modern Rust
    • Teaching the building blocks of a Rust program
  • Library crate (lib.rs) with doc tests

    sample-lib.rs · 4.6 KB (4,734 bytes)

    A library root as it would sit in src/lib.rs of a package named sample-lib: public functions, a trait with a default method, a generic function, //! and /// documentation with examples that cargo test runs as doc tests, and unit tests.

    • Testing `cargo test`, `cargo doc` and doc-test handling
    • An example of a documented public API
  • UTF-8 with BOM and CRLF line endings

    sample-unicode-bom-crlf.rs · 1.9 KB (1,913 bytes)

    Starts with the UTF-8 byte order mark EF BB BF and uses Windows line endings throughout. Prints six sample strings (Latin, Greek, Japanese, Arabic, emoji) with byte and character counts, and shows that rustc ignores the BOM and reads CRLF as LF, even inside a string literal.

    • Testing editors, linters and diff tools on BOM and CRLF files
    • Showing `len()` (bytes) vs `chars().count()`
  • Deliberately broken file (does not compile)

    sample-compile-error.rs · 1.3 KB (1,296 bytes)

    Clearly labelled at the top: it fails with E0382 (use of a moved value) and E0502 (conflicting borrows), and its comments give the fix for each. Nothing in it is harmful.

    • Checking how editors and CI jobs report compile errors
    • Teaching ownership and borrowing errors
  • 100 KB Rust file

    sample-100kb.rs · 100 KB (102,400 bytes)

    A program with a table of the first 13,200 prime numbers that checks every one, padded with comment lines to exactly 102,400 bytes. Needs Rust 1.87 or later.

    • Upload and size-limit tests
    • Editor, highlighter and formatter performance

Ways to test with them

  • Compiler and CI: build sample-main.rs and sample-100kb.rs; both should compile without warnings and print their results. sample-compile-error.rs should fail with exactly two errors, E0382 and E0502.
  • Editions: compile sample-main.rs with plain rustc and then with --edition 2024. It uses let … else, which works in every edition, so both succeed; it's a quick way to show that a bare rustc defaults to 2015 without breaking anything.
  • Encodings and line endings: open sample-unicode-bom-crlf.rs in your editor, run it through rustfmt and your diff tool, and check the BOM and the CRLF endings survive (or are converted the way you expect).
  • Upload limits: sample-100kb.rs is exactly 102,400 bytes, for testing a limit at the boundary.

Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.

Put it online

Have a Rust file? Give it a link.

Drop a .rs file on 99helpers and it gets its own web address. Anyone who opens the link reads the code as plain text in their browser: it is never compiled or run, which makes it a simple way to share code for review, teaching or a bug report.

Questions

Rust files, frequently asked

What is a .rs file?

A Rust source file: plain-text code in the Rust programming language. A compiler turns it into a program or a library; on its own it doesn't run.

How do I run a .rs file?

Install Rust with rustup, then compile and run it: rustc --edition 2024 main.rs followed by ./main (or main.exe on Windows). For a project with a Cargo.toml, run cargo run in its folder instead.

How do I open a .rs file?

Any text editor opens it, since it's plain UTF-8 text. For writing Rust, VS Code with the rust-analyzer extension or RustRover give completion and inline errors.

What's the difference between rustc and cargo?

rustc is the compiler and works on one crate at a time. Cargo is the build tool and package manager: it reads Cargo.toml, downloads dependencies and calls rustc for you. Most projects use Cargo.

What's the difference between main.rs and lib.rs?

src/main.rs is the root of an executable and contains fn main. src/lib.rs is the root of a library that other code can use. A package can have both.

Which Rust edition should I use?

2024 for new code: it's what cargo new sets. Editions are chosen per package in Cargo.toml, and packages of different editions work together, so existing code can stay on its edition.

Is it safe to open a .rs file?

Yes, opening it in an editor only shows text. Building an untrusted Cargo project is riskier: its build scripts and procedural macros run code on your computer during the build.

Can I convert a .rs file into an .exe?

Yes, that's what compiling does. On Windows, rustc main.rs or cargo build --release produces an .exe that runs on other Windows computers without Rust installed.

Related formats

Other file types explained

Keep going

Related

Sources

Last reviewed 27 October 2026.