Rust’s whole value proposition is the borrow checker. These questions check whether a candidate understands ownership and fearless concurrency, not just the syntax.
Hiring a Rust developer is easy. Telling a real one from a convincing résumé is the hard part — and it’s most of what we do. These are grouped by level, because the same question that stretches a junior is a warm-up for a senior.
Junior Rust interview questions
0–2 years
Ownership basics.
What is ownership in Rust?
Each value has a single owner, and when the owner goes out of scope the value is dropped; this gives memory safety without a garbage collector.
Fights the compiler by cloning everything.
What is borrowing?
Accessing a value by reference without taking ownership; the borrow checker enforces the rules at compile time.
Cannot explain why the compiler rejects a second mutable borrow.
What is the difference between &T and &mut T?
A shared immutable reference vs an exclusive mutable one; you can have many shared or one mutable, not both.
Tries to hold a mutable and immutable borrow simultaneously.
What is the difference between String and &str?
String is an owned, growable heap string; &str is a borrowed string slice. APIs usually take &str.
Takes String by value where &str suffices.
What are Option and Result?
Option models presence/absence and Result models success/failure, replacing null and exceptions with explicit handling.
Unwraps everywhere and panics.
What does match do?
Exhaustive pattern matching that the compiler checks for completeness, ideal for enums.
Uses if-else chains and misses cases.
What is Cargo?
Rust’s build tool and package manager handling dependencies, builds, tests and more.
Manages dependencies manually.
What is the difference between a Vec and an array?
A Vec is a growable heap-allocated list; arrays have a fixed compile-time size.
Uses fixed arrays where growth is needed.
Mid-level Rust interview questions
2–5 years
Lifetimes and traits.
What are lifetimes and why do they exist?
Annotations describing how long references are valid so the compiler prevents dangling references; often elided but sometimes explicit.
Cannot reason about why a lifetime annotation is required.
What are traits?
Shared behaviour interfaces implemented for types, enabling polymorphism and generic bounds.
Uses concrete types everywhere and can’t abstract behaviour.
What is the difference between Box, Rc and Arc?
Box is single heap ownership, Rc is shared ownership (single-thread), Arc is thread-safe shared ownership.
Uses Rc across threads and it won’t compile, or reaches for unsafe.
What is interior mutability (RefCell, Mutex)?
Mutating data through a shared reference with runtime-checked borrowing (RefCell) or thread-safe locking (Mutex).
Overuses RefCell and hits runtime borrow panics.
How does error handling with ? work?
The ? operator propagates errors up the call stack, converting types via From, keeping code clean.
Matches and re-wraps errors verbosely everywhere.
What are closures and the Fn traits?
Anonymous functions capturing environment, categorised as Fn/FnMut/FnOnce by how they use captures.
Cannot explain why a closure moves a captured value.
What is the difference between generics and trait objects?
Generics are monomorphised (fast, static dispatch); trait objects (dyn Trait) use dynamic dispatch for runtime flexibility.
Always boxes trait objects without considering static dispatch.
How do iterators work and why are they zero-cost?
Lazy, composable adapters that the compiler optimises down to efficient loops with no runtime overhead.
Collects into intermediate vectors unnecessarily.
Senior Rust interview questions
5+ years
Concurrency and design.
How does Rust guarantee “fearless concurrency”?
The ownership and Send/Sync traits make data races a compile-time error, so shared-state bugs are caught before running.
Cannot explain what Send/Sync mean.
When is unsafe justified and how do you contain it?
For FFI, low-level optimisation or building safe abstractions; keep it minimal, documented, and wrapped in a safe API upholding invariants.
Sprinkles unsafe to silence the borrow checker.
How does async work in Rust?
Futures are polled by a runtime (e.g. Tokio); async/await is zero-cost but requires an executor and care with Send bounds.
Thinks async has a built-in runtime and blocks in async code.
How do you design good APIs with traits and generics?
Small, composable traits, sensible bounds, and leveraging the type system to make illegal states unrepresentable.
Leaky APIs that force callers into clone/unwrap.
How do you optimise Rust performance?
Profile first, avoid needless allocation and cloning, use iterators and slices, and consider data layout — Rust is fast but not immune to bad structure.
Clones liberally to appease the borrow checker and pays for it.
What are common ways people misuse the type system?
Overusing Rc<RefCell> to emulate mutable graphs, cloning to avoid lifetimes, and reaching for unsafe instead of restructuring.
Recreates a garbage-collected style with Rc<RefCell> everywhere.
How do you handle errors idiomatically at scale?
Library-friendly error types (thiserror) and application-level context (anyhow), preserving cause chains.
One giant stringly-typed error.
When is Rust the right or wrong choice?
Right where performance, safety and concurrency matter (systems, infra, performance-critical services); the cost is a steeper learning curve and slower initial development.
Presents Rust as universally the best choice.
Build and score a full interview with our free interview scorecard tool, browse the full question hub, or see how we interview engineers.