How to Use Claude Code for Rust Development: The Complete Workflow
Rust developers live in the terminal. cargo build, cargo test, cargo clippy, cargo fmt, cargo doc — the entire development lifecycle is CLI-first. There is no "Run" button, no integrated build system hiding behind a GUI. Every Rust developer already has a terminal workflow. The question is whether that workflow is organized or chaotic.
Claude Code understands Rust at a deep level. It knows the ownership model, lifetimes, trait bounds, error handling patterns, and the nuances of unsafe. It can explain why the borrow checker is rejecting your code and offer a fix that is idiomatic, not just correct. Combined with Beam for workspace organization, you get the ideal Rust development stack: an AI pair programmer that speaks Rust fluently, inside a terminal organizer built for multi-session workflows.
This guide walks through the complete workflow — from project scaffolding to performance profiling — showing how Claude Code and Beam work together for Rust development.
Setting Up Your Rust Workspace in Beam
A well-organized workspace is the foundation of a productive Rust workflow. Beam lets you create a dedicated Rust development environment where every terminal has a purpose and nothing gets lost.
The ideal Rust workspace layout:
- Tab 1: Claude Code — Your AI pair programmer. This is where you ask questions, generate code, refactor, and debug. Claude Code runs in your project directory so it has full context.
- Tab 2:
cargo watch/cargo run— Live recompilation. Every time Claude Code modifies a file, you see the compiler output immediately in this tab. - Tab 3:
cargo test— Dedicated test runner. Run tests continuously or on-demand without interrupting your Claude Code conversation.
For maximum productivity, use Beam's split panes. Press ⌘⌥⌃T to split your first tab horizontally: Claude Code on the left, compiler output on the right. This gives you an instant feedback loop — ask Claude Code to make a change, and watch the compiler validate it in real time.
Pro Tip: Save Your Rust Layout
Once you have your workspace configured with the right tabs and splits, press ⌘S to save it as a layout. Name it something like "Rust Dev." The next time you start a Rust project, restore the layout and you are instantly in your ideal environment — no setup required.
For larger projects, create multiple workspaces. One workspace per crate keeps things clean:
Workspace 1: "Core Library"
- Tab 1: Claude Code (working on
myapp-core/) - Tab 2:
cargo watch -x check -p myapp-core - Tab 3:
cargo test -p myapp-core
Workspace 2: "CLI Application"
- Tab 1: Claude Code (working on
myapp-cli/) - Tab 2:
cargo run -- --help - Tab 3: Integration tests
Switch between workspaces with ⌘⌥←→. Each workspace maintains its own shell state, so your cargo watch keeps running when you switch contexts.
Scaffolding Rust Projects with Claude Code
Starting a new Rust project involves more than cargo new. You need the right dependencies, feature flags, project structure, and boilerplate. Claude Code handles all of this in a single prompt.
Binary Projects with Argument Parsing
Tell Claude Code what your CLI tool should do, and it generates the complete scaffold:
> Create a new Rust CLI tool called "logparse" that reads log files, filters by log level, and outputs JSON. Use clap for arg parsing, serde for JSON, and anyhow for errors. Set up the project structure with src/main.rs, src/lib.rs, src/parser.rs, and src/output.rs.
Claude Code will generate the Cargo.toml with pinned dependency versions, set up the clap derive-based argument parser, create the module structure with proper mod declarations, and include skeleton implementations for each module. It understands that a well-structured Rust binary separates the CLI interface from the library logic.
Library Crates with Public API Design
Library design in Rust requires careful thought about what is public and what stays private. Claude Code can scaffold a library with a clean API surface:
> Create a Rust library crate for a rate limiter. Public API should expose RateLimiter::new(max_requests, window_duration), .check(), and .reset(). Use a token bucket algorithm internally. Include builder pattern for configuration.
Claude Code will create the public structs and methods in lib.rs, keep implementation details in private submodules, add doc comments with examples on every public item, and set up #[cfg(test)] module skeletons for each file.
Workspace Projects with Multiple Crates
Cargo workspaces are the standard for Rust monorepos. Claude Code understands the workspace Cargo.toml format and inter-crate dependencies:
> Set up a Cargo workspace with three crates: myapp-core (library), myapp-server (binary, depends on core), and myapp-cli (binary, depends on core). Share common dependencies at workspace level. Enable LTO for release builds.
It will generate the root Cargo.toml with [workspace] members and shared [workspace.dependencies], each crate's Cargo.toml referencing workspace dependencies with dep.workspace = true, and a [profile.release] section with lto = true, codegen-units = 1, and strip = true for optimized binaries.
Cargo.toml Expertise
Claude Code knows the Cargo.toml specification deeply. Ask it to add feature flags, conditional compilation targets, or optional dependencies, and it generates correct, idiomatic configuration:
> Add an optional "tls" feature to my library that enables rustls support. When enabled, expose an additional connect_tls() method. Default features should include "tls".
Why Scaffolding with Claude Code Matters
Rust projects have more upfront structure than most languages. Module declarations, pub visibility, feature gates, and Cargo.toml configuration all need to be correct before you write a single line of business logic. Claude Code eliminates the boilerplate phase entirely, letting you jump straight into the problem you are actually trying to solve.
Rust-Specific Claude Code Workflows
Rust has a unique set of concepts that trip up developers at every experience level. Claude Code understands them all, and more importantly, it can explain why the compiler is complaining and offer idiomatic solutions.
Ownership and Borrowing
The borrow checker is Rust's defining feature and its steepest learning curve. When you hit a lifetime error, paste the compiler output into Claude Code:
> Fix this error:
error[E0597]: `data` does not live long enough
--> src/main.rs:12:22
|
12 | let reference = &data;
| ^^^^ borrowed value does not live long enough
13 | }
| - `data` dropped here while still borrowed
Claude Code does not just fix the code. It explains the ownership problem: what owns the data, what borrows it, and why the lifetimes do not align. Then it offers the right solution, whether that is restructuring the code, using Arc for shared ownership, cloning where appropriate, or adjusting lifetime annotations.
Common ownership scenarios Claude Code handles well:
- Moving values into closures — when to use
move, when to borrow, when to clone - Self-referential structs — why they are problematic and alternatives like
ouroborosor index-based approaches - Lifetime elision — when you need explicit lifetimes and when the compiler infers them
- Interior mutability — choosing between
Cell,RefCell,Mutex, andRwLock
Trait Implementations
Rust traits are pervasive. Almost every struct needs Debug, most need Display, and many need From/Into conversions. Instead of writing these by hand, ask Claude Code:
> Implement Display, Debug, From<io::Error>, From<serde_json::Error>, and Into<StatusCode> for my AppError enum. Also implement the Error trait properly.
Claude Code generates all the trait implementations with correct match arms, proper formatting, and idiomatic Rust style. It knows when to use #[derive(Debug)] versus a manual implementation, when Display should delegate to inner types, and how to chain From implementations for ergonomic error conversion with the ? operator.
Error Handling Patterns
Rust's error handling ecosystem has converged on two crates: thiserror for libraries and anyhow for applications. Claude Code knows which to use and when:
> Create an error type for my HTTP client library using thiserror. It should cover connection errors, timeout errors, invalid URL, HTTP status errors (with the status code), and deserialization errors. Include From impls for reqwest::Error and serde_json::Error.
For application code, Claude Code will use anyhow for quick, flexible error handling with context:
> Convert this function to use anyhow. Add .context() calls with meaningful error messages at each failure point.
The result is error handling that gives you clear error chains when something fails, without the verbosity of manually writing error types for application-level code.
Async Rust
Async Rust is powerful but notoriously complex. Pin, Future, Stream, Send + Sync bounds, and the distinction between tokio and async-std create a steep learning curve. Claude Code navigates this confidently:
> Create an async HTTP server using axum with three routes: GET /health, POST /data that accepts JSON and stores it, and GET /data/:id that retrieves it. Use tokio with multi- threaded runtime. Include graceful shutdown on SIGTERM.
Claude Code handles the common async pain points:
Send + Syncbounds — It knows thattokio::spawnrequiresSendfutures and will structure code to satisfy thisPin<Box<dyn Future>>— When you need type-erased futures, it generates the correct boxing- Stream processing — Using
tokio_streamorfutures::Streamfor async iteration - Select and join — Concurrent task management with
tokio::select!andtokio::join! - Async trait methods — Using the
async-traitcrate or Rust's native async traits (stabilized in recent editions)
Unsafe Code Review
Sometimes unsafe is necessary. When it is, Claude Code can audit it and suggest safe alternatives:
> Audit this unsafe block. Is it sound? Can it be replaced with
safe code?
unsafe {
let ptr = data.as_ptr();
let slice = std::slice::from_raw_parts(ptr, data.len());
process(slice);
}
Claude Code will analyze whether the invariants required by from_raw_parts are maintained (valid pointer, correct length, proper alignment, no aliasing), and almost always suggest a safe alternative that performs identically. In this case, it would point out that the unsafe block is entirely unnecessary since data is already a slice.
Macro Generation
Rust macros — both declarative (macro_rules!) and procedural (derive macros) — are powerful but have notoriously difficult syntax. Claude Code excels here because macro patterns are repetitive and well-defined:
> Create a declarative macro called impl_from_str that takes a struct name and a list of field:type pairs, and generates a FromStr implementation that parses a comma-separated string into the struct.
Claude Code generates the macro with proper hygiene, clear token tree patterns, and helpful compile error messages using compile_error!. For derive macros, it can generate the full proc-macro crate structure with syn and quote.
Building CLI Tools in Rust
Rust is the dominant language for modern CLI tools. ripgrep, bat, fd, exa, zoxide, delta, hyperfine — the tools developers love most are written in Rust. Claude Code can help you build production-quality CLI tools with the same patterns.
The CLI Tool Stack
Tell Claude Code what your tool does, and it assembles the right crates:
clap— Argument parsing with derive macros. Claude Code generates the#[derive(Parser)]struct with help text, subcommands, and validation.indicatif— Progress bars and spinners. Claude Code sets up multi-progress bars for parallel operations, progress templates with ETA, and automatic tick intervals.dialoguer— Interactive prompts. Confirmation dialogs, selection menus, text input with validation, and password input.colored— Terminal colors and formatting. Error messages in red, success in green, warnings in yellow, all respectingNO_COLOR.tokio— For async I/O-heavy tools. Claude Code knows when async is justified (network requests, concurrent file operations) and when synchronous code is simpler and faster.
Example: Building a Log Analyzer
Here is a real workflow using Claude Code and Beam for building a CLI tool:
Step 1: In your Claude Code pane, scaffold the project:
> Create a CLI tool called "loggrep" that searches structured JSON log files. It should support filtering by log level, time range, and regex pattern matching on message fields. Output as formatted text or JSON. Use clap, serde, regex, chrono, and colored.
Step 2: In your cargo watch pane, start the watcher:
$ cargo watch -x check -x clippy
Step 3: Iterate with Claude Code. Ask it to add features one at a time:
> Add a --follow flag that watches the file for new lines, like tail -f. Use notify for file watching.
> Add progress bar using indicatif when processing large files. Show bytes processed and estimated time remaining.
> Add shell completions generation. clap_complete for bash, zsh, and fish. Add a "completions" subcommand.
Each time Claude Code modifies a file, you see the compiler output in your other pane immediately. No context switching, no running commands manually. The feedback loop is instantaneous.
Beam Advantage: Split-Pane Feedback Loop
This is where Beam's split panes shine for Rust development. The Rust compiler is famously strict — and famously helpful. When Claude Code makes a change, the compiler catches issues within seconds in your adjacent pane. You can copy the error back to Claude Code and iterate without leaving your workspace. No tab switching, no lost context.
Testing in Rust with Claude Code
Rust has testing built into the language and toolchain. No test runner framework to install, no configuration files to maintain. Claude Code leverages this to generate comprehensive tests with minimal prompting.
Unit Tests
Rust convention places unit tests in a #[cfg(test)] module at the bottom of each file. Claude Code follows this convention automatically:
> Write unit tests for the parse_log_entry function. Cover valid JSON entries, malformed JSON, missing required fields, edge cases for timestamp parsing, and unicode in message fields.
Claude Code generates the mod tests block with #[test] functions, uses descriptive test names like test_parse_valid_entry_with_all_fields, includes both success and failure cases, and uses assert_eq! with meaningful messages.
Integration Tests
Integration tests live in the /tests directory and test your crate's public API. Claude Code knows the distinction:
> Create integration tests for the loggrep library. Test the full pipeline: read file, apply filters, produce output. Use tempfile for test fixtures.
It will create files in tests/ that import your crate as an external dependency, set up test fixtures with tempfile::NamedTempFile, and test the full workflow from input to output.
Doc Tests
Rust's doc tests are unique — code examples in documentation are compiled and run as tests. Claude Code writes doc examples that serve dual purpose: they document the API and verify it works:
> Add documentation with examples to all public functions in the rate_limiter module. Every example should be a complete, runnable doc test.
Property-Based Testing
For functions with complex invariants, Claude Code can set up property-based tests with proptest:
> Add property-based tests for the serialization module. Verify that for any valid Config value, serialize then deserialize produces the original value (roundtrip property).
Claude Code generates the proptest! macro invocations, custom Arbitrary implementations for your types, and targeted strategies that generate meaningful test inputs rather than purely random data.
Organizing Test Output in Beam
Dedicate a full tab to cargo test. Use the --nocapture flag to see println! output from tests, and --test-threads=1 when debugging test interactions. Beam keeps this output visible and scrollable while you work with Claude Code in another pane.
For test-driven development, run:
$ cargo watch -x "test -- --nocapture"
Every time Claude Code saves a file, the tests re-run automatically in your dedicated test tab.
The Cargo Watch Workflow
cargo-watch is the secret weapon for Rust's compile-check-test cycle. It watches your source files and re-runs commands on every change. Combined with Beam's split panes, it creates a development experience that rivals any IDE.
Setting It Up
Install cargo-watch if you have not already:
$ cargo install cargo-watch
Then in your dedicated Beam pane, run:
$ cargo watch -x check -x test -x run
This command chains three operations: first cargo check (fast type checking), then cargo test (if check passes), then cargo run (if tests pass). The chain short-circuits on failure, so you get the fastest possible feedback.
The Split-Pane Setup
The ideal layout in Beam:
- Left pane: Claude Code session, where you are writing and refactoring code
- Right pane:
cargo watch -x check -x clippy, showing real-time compiler and lint output
When Claude Code modifies a Rust file, cargo-watch detects the change within a second. You see either green "Finished" messages or compiler errors. If there are errors, you can paste them directly back to Claude Code:
> I'm getting this error from cargo check:
error[E0382]: borrow of moved value: `config`
--> src/main.rs:45:20
|
42 | let server = Server::new(config);
| ------ value moved here
45 | println!("{}", config.port);
| ^^^^^^^^^^^ value borrowed here after move
Claude Code will explain that Server::new took ownership of config, and suggest either passing a reference (&config), cloning the value, or restructuring the code to access config.port before the move.
Advanced Cargo Watch Configurations
For different stages of development, adjust the cargo watch command:
- Early development:
cargo watch -x check— fastest feedback, just type checking - Feature complete:
cargo watch -x check -x test— type checking plus tests - Pre-commit:
cargo watch -x check -x clippy -x test— full lint and test suite - Specific crate:
cargo watch -x "test -p myapp-core"— focus on one crate in a workspace
Managing Rust Workspaces
As Rust projects grow, they naturally split into multiple crates within a Cargo workspace. This is where Beam's workspace-per-crate organization becomes essential.
One Beam Workspace Per Crate
For a Cargo workspace with three crates (core, server, cli), create three Beam workspaces:
Beam Workspace "core":
- Tab 1: Claude Code, working directory set to
crates/core/ - Tab 2:
cargo watch -x "test -p myapp-core"
Beam Workspace "server":
- Tab 1: Claude Code, working directory set to
crates/server/ - Tab 2:
cargo run -p myapp-server - Tab 3:
curlcommands for API testing
Beam Workspace "cli":
- Tab 1: Claude Code, working directory set to
crates/cli/ - Tab 2:
cargo run -p myapp-cli -- --help
Shared Dependencies and Feature Flags
Claude Code understands Cargo workspace dependency management. Ask it to refactor dependencies to the workspace level:
> Move all shared dependencies (serde, tokio, tracing) to workspace-level dependencies. Update each crate's Cargo.toml to use dep.workspace = true syntax.
Or manage feature flags across crates:
> Add a "metrics" feature to the core crate that adds prometheus metrics to all public functions. The server crate should enable this feature by default, but the CLI crate should not.
Claude Code Context Per Crate
Claude Code uses memory files to maintain project context. For a multi-crate workspace, you can have a memory file at the workspace root with architectural decisions and one per crate with crate-specific context. Claude Code reads these automatically and understands the relationships between crates.
This means when you are working on the server crate and you ask Claude Code to add a feature, it already knows the API surface of core and can generate code that uses it correctly.
Performance Profiling with Claude Code
Rust developers care deeply about performance. Claude Code can help you measure, analyze, and optimize your code.
Benchmarking with Criterion
Claude Code sets up criterion benchmarks with proper statistical methodology:
> Create benchmarks for the parse_log_entry function using criterion. Benchmark with small (100 byte), medium (1KB), and large (10KB) log entries. Include throughput measurement.
It generates the benches/ directory structure, the benchmark harness with criterion_group! and criterion_main! macros, and parameterized benchmarks that measure both latency and throughput.
Run the benchmarks in a dedicated Beam tab:
$ cargo bench
Criterion generates HTML reports with statistical analysis. Claude Code can then help you interpret the results and identify optimization opportunities.
Flamegraph Analysis
For runtime profiling, the cargo-flamegraph tool generates interactive SVG flamegraphs. Claude Code can help you set it up and interpret the results:
> Set up flamegraph profiling for the server binary. Add a /debug/profile endpoint that records 10 seconds of CPU activity and returns a flamegraph SVG.
After generating a flamegraph, describe what you see to Claude Code:
> The flamegraph shows 40% of time in serde_json::from_str and 25% in regex::Regex::find. How can I optimize these?
Claude Code will suggest targeted optimizations: using serde_json::from_slice instead of from_str to avoid a UTF-8 validation pass, compiling the regex once with lazy_static! or std::sync::OnceLock instead of per-call, or switching to simd-json for SIMD-accelerated parsing.
Compiler Optimizations
Claude Code knows the Rust compiler's optimization knobs:
> Optimize my release build for binary size. I want the smallest possible binary for distribution.
It will configure:
opt-level = "z"for size optimizationlto = truefor link-time optimizationcodegen-units = 1for maximum optimization opportunitystrip = trueto remove debug symbolspanic = "abort"to eliminate unwinding code
Or for maximum runtime performance:
> Optimize for speed. I need the fastest possible execution for this data processing pipeline.
Claude Code will set opt-level = 3, enable lto = "fat", set target-cpu = "native" in RUSTFLAGS, and suggest algorithmic improvements based on your code's hot paths.
Real-World Rust + Claude Code Patterns
Here are patterns that come up repeatedly in real Rust development, where Claude Code provides significant value:
Serde Customization
Almost every Rust project uses serde, and almost every project needs custom serialization at some point. Claude Code handles the full spectrum:
- Rename fields —
#[serde(rename = "camelCase")],#[serde(rename_all)] - Default values —
#[serde(default)]with custom default functions - Custom deserializers — When the derive macro is not flexible enough
- Flattened and adjacent tagging — For complex JSON shapes
- Untagged enums — For parsing JSON that could be multiple types
Tracing and Observability
The tracing ecosystem is the standard for structured logging in Rust. Claude Code sets up the full stack:
> Add structured logging using tracing. Set up tracing-subscriber with JSON output for production and pretty-printed for dev. Add spans to all public functions and instrument async methods.
Cross-Compilation
Claude Code knows Rust's cross-compilation targets and toolchain management:
> Set up cross-compilation for Linux x86_64 and ARM64 from macOS. Add a Makefile with targets for each platform. Use cross for Docker-based compilation.
Build Rust Projects Faster with Beam
The terminal is every Rust developer's IDE. Beam organizes it with workspaces, tabs, and split panes designed for multi-session workflows like Claude Code + cargo watch.
Download Beam for macOSSummary
Rust development is inherently terminal-centric. Every tool in the Rust ecosystem — cargo, clippy, rustfmt, rustup, cargo-watch, cargo-bench — runs in the terminal. Claude Code operates in the same environment, understanding Rust at a deep enough level to handle ownership, lifetimes, traits, async patterns, macros, and performance optimization.
Beam ties it all together by organizing the parallel terminal sessions that Rust development demands:
- Workspaces per crate or project for clean context separation
- Split panes for the Claude Code + cargo watch instant feedback loop
- Dedicated tabs for tests, benchmarks, and running binaries
- Saved layouts so your entire Rust environment restores in one keystroke
- Quick Switcher (⌘P) to jump between crates and sessions instantly
If you are building in Rust and working in the terminal, this is the workflow to adopt. Claude Code for the intelligence. Beam for the organization. Cargo for everything else.