Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

For a new Rust codebase in 2026, start with Cargo, set edition = "2024", record the exact compiler version your team supports, and make formatting, linting, tests, and documentation repeatable in CI. Use a workspace when multiple crates share release or dependency policy; keep domain APIs in focused library crates and executable wiring in binary crates.

The Rust Project’s 2026 beta Book states that its examples assume Rust 1.97.0 or later with Rust 2024 enabled. A later report from the Book’s main branch names Rust 1.98.0, released August 20, 2026. Treat the compiler as a moving release line: pin and document the version you actually build and test rather than implying that every 2026 toolchain behaves identically.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Set the 2026 baseline before writing application code

Use Rust 2024 for new projects

Rust editions select language and library idioms without splitting the ecosystem into incompatible languages. For a project started in 2026, put the edition in every package manifest:

[package]
name = "billing-core"
version = "0.1.0"
edition = "2024"

The Rust Project’s current beta Book phrases the baseline precisely: “This version of the text assumes you’re using Rust 1.97.0 (released 2026-07-09) or later with edition = "2024" in the Cargo.toml file of all projects to configure them to use Rust 2024 Edition idioms.”

Edition selection is a repository decision, not an editor preference. Set it consistently for every package in a workspace, then check in the manifest changes so a clean checkout uses the same language assumptions.

Record a minimum supported toolchain

Write the minimum supported Rust version (MSRV) in the README or contributor documentation and pin the development toolchain when reproducibility matters. For example, a repository may test Rust 1.98.0 if that is the version the team has selected and verified. The important part is to name the exact compiler, date the decision, and update it deliberately as releases arrive.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A rust-toolchain.toml file can make local setup explicit:

[toolchain]
channel = "1.98.0"
components = ["rustfmt", "clippy"]

If your support policy is broader than one compiler, distinguish the pinned development toolchain from the oldest compiler you promise to support. Run CI against the MSRV when compatibility is part of your contract, and run the pinned current toolchain for normal development.

Make Cargo the project boundary

Cargo is Rust’s build tool, package manager, dependency resolver, workspace coordinator, and conventional entry point for tests, documentation, formatting, and linting. A Cargo package should describe one coherent deliverable. Avoid treating an IDE project or an ad-hoc directory of source files as the architectural boundary; Cargo metadata is what other tools understand.

Keep the root manifest, lockfile policy, toolchain file, formatting configuration, and CI workflow under version control. This gives a new contributor one discoverable place to learn how the project is built and checked.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a repository shape that matches the code

When one package is enough

A single package is appropriate when one executable or one library owns the domain and there is no independent release boundary. Keep src/lib.rs as the public library root or src/main.rs as the binary root. Even in a small package, separate domain logic from adapters such as HTTP, command-line parsing, databases, or message transports.

When to introduce a workspace

Use a workspace when several crates share a release cadence, dependency policy, test command, or publishing boundary. Typical members include a domain library, an application binary, and a small integration-test or tooling crate. A workspace lets Cargo operate on them together while preserving clear crate-level APIs.

acme-platform/
├── Cargo.toml
├── Cargo.lock
├── rust-toolchain.toml
├── rustfmt.toml
├── crates/
│   ├── domain/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   └── service/
│       ├── Cargo.toml
│       └── src/
│           └── main.rs
└── tests/

The root workspace manifest should state membership and central policy. Package manifests should still declare their own names, versions, edition, and direct dependencies so each crate remains understandable on its own.

Question Single package Workspace
How many Cargo packages? One coherent library or executable Several crates with explicit boundaries
What is shared? One package’s dependencies and checks Release, dependency, and CI policy across members
Where does wiring live? The package binary target Binary crates depend on focused library crates
When is it justified? No independent crate boundary is needed Separate APIs, owners, or release concerns must remain visible

Do not create a workspace merely to make a directory look larger. Splitting code increases dependency edges, feature combinations, and documentation work. Add a crate when the boundary improves ownership, reuse, testing, or release control.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Design crates and modules around responsibilities

Keep library crates focused on domain APIs

A library crate should expose concepts another crate can use without knowing how the application is started. Put parsing, validation, state transitions, and domain rules behind types and functions that express their contracts. Keep network clients, process startup, configuration loading, and logging setup in the executable or an adapter crate.

One useful dependency direction is:

  • Domain library: value types, invariants, domain errors, and pure or mostly deterministic operations.
  • Application library: orchestration and use cases that combine domain operations with ports or traits.
  • Binary: configuration, dependency construction, transport handlers, command-line wiring, and process exit behavior.

The names are not mandatory. The rule is that a lower-level crate should not need to know how a higher-level binary is launched.

Give modules one reason to change

Prefer small modules whose contents change for a related reason: authentication policy, invoice calculation, persistence mapping, or an HTTP handler should not all live in one file. A module boundary is useful when it limits what callers can depend on and makes tests target a behavior rather than an implementation detail.

Keep internal items private by default. Promote a type or function to pub only when another crate genuinely needs it. A smaller public surface is easier to document, test, and evolve.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make ownership and borrowing visible

Public signatures are contracts. Choose owned values when the callee must retain data, borrowed references when the call is synchronous and does not outlive its input, and explicit shared or mutable ownership types when the concurrency model requires them. Avoid hiding expensive cloning or lifetime assumptions behind generic helper functions.

When a lifetime or ownership rule is non-obvious, encode it in a named type or a narrower function rather than relying on comments that callers cannot enforce. Compile-time guarantees are most valuable when a reader can see the invariant in the API.

Define error behavior at boundaries

Use domain-specific error types where callers need to distinguish failures. At a crate boundary, decide which errors are recoverable, which should be retried, and which indicate a programming or invariant violation. Convert low-level errors to a stable public error at the boundary instead of leaking every dependency’s error type through your API.

For binaries, map failures to an exit status and a useful diagnostic. For libraries, return errors that preserve enough context for the caller to decide what happens next. Document whether an operation can partially apply, mutate state before failing, or guarantee atomic behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Isolate unsafe code

Keep unsafe blocks behind a small, documented safe interface. For every block, state the invariant that makes the operation valid: pointer alignment, initialized memory, aliasing rules, thread ownership, or an external API guarantee. Do not spread isolated unsafe operations through otherwise safe business logic.

Review unsafe code separately from ordinary refactoring. The safe wrapper should make invalid states unrepresentable where practical, and its tests should exercise boundary conditions that could violate the documented invariant.

Use feature flags sparingly

Feature flags multiply the configurations that must compile, test, document, and support. Add a flag when it represents a real optional capability, platform choice, or dependency cost. Name features by behavior rather than by an incidental implementation detail, and document supported combinations.

Every feature should have a CI path that proves it still builds. If combinations are intentionally unsupported, state that in the crate documentation instead of allowing users to discover it through an opaque compiler failure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Write manifests that communicate the architecture

Root workspace manifest

[workspace]
members = [
    "crates/domain",
    "crates/service",
]

Keep the root manifest concerned with workspace membership and shared policy. Each member manifest should identify its own package and direct dependencies. This separation makes it clear which crate owns a dependency and prevents an executable’s convenience dependency from silently becoming part of a domain API.

Library package manifest

[package]
name = "domain"
version = "0.1.0"
edition = "2024"

[dependencies]

Start with an empty dependency list when the domain does not need external crates. Adding a dependency has compile-time, security, upgrade, and feature implications; justify it in the same review that changes the manifest.

Binary package manifest

[package]
name = "service"
version = "0.1.0"
edition = "2024"

[dependencies]
domain = { path = "../domain" }

The binary depends on the library through a visible path dependency. This keeps executable wiring out of the domain crate and makes the direction of coupling obvious in Cargo metadata.

Make formatting, linting, tests, and docs a CI contract

Run the same checks locally and in CI

At minimum, make these commands part of the repository’s repeatable check:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. cargo fmt --check
  2. cargo clippy --all-targets --all-features -- -D warnings
  3. cargo test --all-targets --all-features
  4. cargo doc --no-deps

cargo fmt --check fails when committed files are not formatted. Clippy is run for every target and feature combination requested by the command, and -D warnings turns warnings into failures. The test command exercises all targets and enabled features. Documentation generation catches broken intra-project documentation and ensures the public API can be rendered without building dependency documentation.

Run these commands from the workspace root in CI. A shell job can stop at the first failure:

set -euo pipefail
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo doc --no-deps

Align rustfmt across editors and Cargo

Rust 2024 introduces an edition-aware formatting choice. The Edition Guide documents style_edition = "2024". Put the setting in the repository’s rustfmt.toml when you want the style edition to be explicit:

style_edition = "2024"

Configure editor format-on-save to invoke the same rustfmt toolchain used by Cargo. Direct rustfmt or editor defaults can otherwise differ from Cargo’s edition-aware behavior, producing formatting churn even when the code itself has not changed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When formatting changes unexpectedly, first check the compiler and rustfmt versions, then inspect rustfmt.toml and the editor’s formatter selection. Do not solve a style mismatch by disabling the CI check; make the chosen style reproducible instead.

Test behavior next to the code that protects it

Unit-test domain invariants

Place unit tests near the module or behavior they protect. Test valid transitions, rejected inputs, boundary values, and error classification. A test should explain the invariant: for example, that an invoice cannot move from paid back to pending, or that a parser rejects a missing field with a stable error category.

Use integration tests for public contracts

Integration tests should call the crate as an external user would. They are especially valuable for visibility rules, serialization formats, error types, and workspace boundaries. Keep implementation-only tests in the module so a public API does not grow merely to make a test compile.

Exercise targets and features

The all-targets and all-features CI command is a baseline, not proof that every feature combination is meaningful. Add focused jobs for combinations that represent supported products or platforms. If a feature is mutually exclusive with another, encode that rule in documentation and test the supported paths explicitly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Document examples that compile

Public APIs should explain ownership, error behavior, and invariants in rustdoc. Prefer examples that compile as documentation tests when possible; they serve as both guidance and an early warning when an API changes. The cargo doc --no-deps job ensures the project’s own documentation remains buildable without expanding the job to every dependency.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Review design choices with consistent axes

When two structures can both work, review them against the same questions rather than choosing by taste:

Axis Review question
Ownership and lifetime clarity Can a caller understand who owns data, how long borrows last, and where mutation occurs?
Public API stability Does the boundary expose only contracts you are prepared to support?
Compile-time and runtime cost Will this abstraction increase build work, allocations, dispatch, or startup cost that matters to the product?
Testability Can behavior be tested without constructing unrelated infrastructure?
Error propagation Can failures retain the context and distinctions a caller needs?
Unsafe surface area Is unsafe code isolated, justified, and covered by tests for its invariant?
Dependency and feature complexity How many crates and supported combinations must the team maintain?
Documentation and observability Can a new maintainer understand the boundary and diagnose failures in production?

Choose the simplest structure that makes invariants and failure modes easy to inspect. A more abstract design is justified when it materially improves one of these axes without making the others opaque.

Keep documentation and maintenance part of the design

Explain the repository’s contract

The README or contributor guide should state the Rust edition, pinned development toolchain, minimum supported compiler policy, workspace layout, required components, and the exact CI commands. A contributor should not have to infer these decisions from a failed build.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Document public invariants

Rust’s type system can enforce many rules, but not every business invariant. Explain what a public type guarantees, what it does not guarantee, and which errors callers must handle. If an operation is not thread-safe, blocking, lossy, or expensive, say so where the API is introduced.

Keep observability at the executable boundary

Libraries should return structured errors and useful context; binaries should decide how to log, display, retry, or terminate. This keeps domain crates reusable while giving each executable control over deployment-specific diagnostics.

Use a current Rust book alongside the repository

The Rust Programming Language, 3rd Edition is a current physical companion for Rust 2024 project work. No Starch Press lists it at 624 pages, published in March 2026, with coverage of program design, Cargo, testing, documentation, and refactoring. Those subjects map directly to the base decisions in this guide: establish Cargo boundaries, make behavior testable, and treat documentation as part of the API.

Use the book to build shared vocabulary, but keep the repository’s toolchain file and CI output authoritative for the compiler version your team supports. The Book’s assumptions can move during the 2026 release cycle, while your project needs a reproducible contract.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Implementation checklist for a new 2026 repository

  1. Create the project with Cargo and commit the generated manifest.
  2. Set edition = "2024" in every package manifest.
  3. Choose and document an MSRV; pin the development compiler when reproducibility requires it.
  4. Decide whether one package is sufficient before introducing a workspace.
  5. Place domain rules in focused library crates and executable wiring in binaries.
  6. Keep modules cohesive and private by default; expose only stable contracts.
  7. Define error types and failure behavior at crate and process boundaries.
  8. Isolate every unsafe block behind a documented safe interface.
  9. Add feature flags only for real supported variations and test their combinations.
  10. Commit formatting configuration, including the chosen Rust 2024 style edition when needed.
  11. Run cargo fmt --check, Clippy with warnings denied, all-target and all-feature tests, and cargo doc --no-deps in CI.
  12. Review ownership, API stability, costs, testability, errors, unsafe code, dependency complexity, and documentation before merging structural changes.

Troubleshoot common setup failures

Formatting passes locally but fails in CI

Compare the compiler and rustfmt versions first. Confirm that the editor uses the repository toolchain and that rustfmt.toml specifies the intended style edition. Reformat with the pinned toolchain, review the diff, and commit the result.

Clippy fails after a dependency or feature change

Run the exact CI command locally, including --all-targets --all-features -- -D warnings. The failing code may exist only in an example, test target, or optional feature. Fix the warning or narrow the supported feature combinations and document that decision.

Tests pass for the binary but not the workspace

Run the command from the workspace root and inspect each member’s targets. A binary-only command can miss library tests, examples, benches, or integration targets elsewhere in the repository. Keep crate-specific tests near their behavior and let the workspace job verify the complete graph.

A public API change breaks downstream code

Check whether an internal type was exposed accidentally or whether an error, ownership, or lifetime contract changed. Restore the narrow boundary, add an integration test that represents the supported caller, and document intentional breaking changes before releasing them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.