You know that feeling when you finally get your development environment just right? After months of tweaking, testing, and honestly getting frustrated with slow compile times and memory-hungry language servers, I think I've cracked the code for the perfect Rust setup.
I've been building Rust projects for a while now β from my Discord bot library rustycord to puzzle solvers like sudoko and sudoko-tui, and even a hardware automation system for PhotoBooth. Through all these projects, I've learned what actually matters in a development setup and what's just noise.
Let me walk you through how I've configured VS Code on Garuda Linux to make Rust development feel effortless. This isn't just another "here's my dotfiles" post β this is the setup that's helped me ship real projects and actually enjoy the process.
Before diving into the VS Code magic, let me tell you why I fell in love with Garuda GNOME for my daily coding sessions:
Performance That Actually Matters: Look, I'm not going to lie β Rust compilation can be slow. But Garuda's out-of-the-box optimizations, especially that Zen kernel, make a real difference. When you're waiting for cargo build
to finish for the hundredth time today, every second counts.
AUR is a Game Changer: Coming from Ubuntu, having access to the AUR feels like having superpowers. Need the latest version of a tool? It's probably in AUR. Want to try some experimental Rust tooling? AUR has got you covered. No more adding sketchy PPAs or compiling from source at 2 AM.
It Just Worksβ’: I know this sounds clichΓ©, but after distro-hopping for years, I appreciate something that doesn't break when I update it. Garuda strikes that perfect balance β powerful enough for serious development, stable enough that I'm not troubleshooting driver issues when I should be writing code.
Beautiful and Functional: Let's be honest β we spend 8+ hours a day looking at our screens. Garuda's aesthetic doesn't hurt, and the GNOME workflow with their customizations actually makes me more productive.
Here's my first piece of advice: ignore your package manager for Rust installation. I know it's tempting to just run sudo pacman -S rust
, but trust me on this one:
# Install rustup (the official Rust toolchain installer)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add cargo to your PATH (add this to your ~/.zshrc since we're on Garuda)
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Install the latest stable toolchain
rustup install stable
rustup default stable
# Add the essential components (you'll thank me later)
rustup component add clippy rustfmt rust-src rust-analyzer
Why rustup over pacman? Simple: you get better control over versions, easier switching between toolchains for testing, and you're always up-to-date with the latest Rust releases. When you're working on multiple projects that might need different Rust versions, you'll appreciate this flexibility.
Now, let's get to the meat of this post β my VS Code configuration. I use a dedicated profile called "Hrithik Rust" for all my Rust development, which keeps my setup clean and isolated.
Here are the extensions that make my Rust development experience smooth:
{
"rust-lang.rust-analyzer": "The language server that makes everything possible",
"tamasfe.even-better-toml": "Because Cargo.toml deserves syntax highlighting",
"dustypomerleau.rust-syntax": "Enhanced Rust syntax highlighting",
"tauri-apps.tauri-vscode": "Essential for my Tauri projects like SpendLite",
"github.copilot": "AI pair programming that actually understands Rust",
"github.copilot-chat": "When I need to brainstorm Rust solutions",
"eamodio.gitlens": "Git integration that saves my sanity",
"shd101wyy.markdown-preview-enhanced": "For documentation and README files"
}
Here's the configuration that makes everything work smoothly together:
{
"editor.fontFamily": "cascadia code nf",
"editor.fontSize": 13,
"editor.fontWeight": "600",
"workbench.colorTheme": "Bluloco Dark Italic",
"workbench.iconTheme": "bearded-icons",
"workbench.productIconTheme": "fluent-icons",
// Auto-save is crucial for rust-analyzer feedback
"files.autoSave": "afterDelay",
"editor.formatOnSave": true,
// Rust-specific settings that improve performance
"rust-analyzer.cargo.loadOutDirsFromCheck": false,
"rust-analyzer.procMacro.enable": false,
"rust-analyzer.memoryUsage": "low",
// Exclude directories to improve performance
"rust-analyzer.files.excludeDirs": [
"node_modules",
"target",
"dist",
"build"
],
"files.watcherExclude": {
"**/node_modules/**": true,
"**/target/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/target": true
},
// GitHub Copilot configuration
"github.copilot.enable": {
"*": true,
"rust": true
},
// Terminal and debugging
"debug.allowBreakpointsEverywhere": true,
"terminal.integrated.fontWeightBold": "bold"
}
Let me explain some of the key choices:
Font Choice: Cascadia Code NF with weight 600 gives me excellent readability for Rust's sometimes verbose syntax. The Nerd Font variant includes icons that various extensions use.
Performance Optimizations: Those rust-analyzer
settings might seem limiting, but they're crucial when working on larger projects. I learned this the hard way when rust-analyzer was consuming 8GB+ RAM on my PhotoBooth project.
File Exclusions: Excluding target/
directories from search and file watching is essential. Rust's compilation artifacts can be massive, and you don't want your editor scanning through them.
When I start a new Rust project, here's my typical setup:
# Create new project
cargo new my-awesome-project
cd my-awesome-project
# Initialize git (if not already done)
git init
# Create a .gitignore if cargo didn't
echo "/target" > .gitignore
echo "Cargo.lock" >> .gitignore # Only for libraries
# Open in VS Code with the Rust profile
code --profile "Hrithik Rust" .
I almost always add these to my projects:
[profile.dev]
# Faster compilation for development
opt-level = 1
[profile.release]
# Maximum optimization for release builds
opt-level = 3
lto = true
codegen-units = 1
panic = "abort"
# Development dependencies I commonly use
[dev-dependencies]
tokio-test = "0.4" # For async testing
criterion = "0.5" # For benchmarking
These are the commands I use most frequently:
# Check code without building
cargo check
# Run with automatic recompilation
cargo watch -x run
# Run tests in watch mode
cargo watch -x test
# Format code (configured to run on save)
cargo fmt
# Lint code
cargo clippy
# Build for release
cargo build --release
# Generate documentation
cargo doc --open
Here's my launch.json
configuration for debugging Rust applications:
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable",
"cargo": {
"args": [
"build",
"--bin=${workspaceFolderBasename}",
"--package=${workspaceFolderBasename}"
],
"filter": {
"name": "${workspaceFolderBasename}",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=${workspaceFolderBasename}",
"--package=${workspaceFolderBasename}"
],
"filter": {
"name": "${workspaceFolderBasename}",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}
Let me share how this setup has helped me with my actual projects:
For rustycord, the async nature and complex type systems really benefited from rust-analyzer's excellent type inference. The auto-completion for async/await patterns and the instant error checking saved me countless hours.
// Example from rustycord - VS Code makes this a breeze
impl EventHandler for MyBot {
async fn message(&self, ctx: Context, msg: Message) -> Result<()> {
if msg.content == "!ping" {
msg.channel_id.say(&ctx.http, "Pong!").await?;
}
Ok(())
}
}
When working on my sudoko crates, the integrated benchmarking and profiling features helped me optimize the solving algorithms. The debugging setup made it easy to step through recursive solving functions.
The PhotoBooth project involves a lot of FFI (Foreign Function Interface) for camera control. VS Code's debugging capabilities were crucial for working with unsafe code blocks and C library integrations.
I use .vscode/settings.json
in each project to override global settings:
{
"rust-analyzer.cargo.features": ["feature1", "feature2"],
"rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu"
}
I've created custom snippets for common Rust patterns:
{
"tokio main": {
"prefix": "tokio-main",
"body": [
"#[tokio::main]",
"async fn main() -> Result<(), Box<dyn std::error::Error>> {",
" ${1:// Your code here}",
" Ok(())",
"}"
]
}
}
My tasks.json
for common Rust operations:
{
"version": "2.0.0",
"tasks": [
{
"type": "cargo",
"command": "check",
"group": "build",
"label": "rust: cargo check"
},
{
"type": "cargo",
"command": "test",
"group": "test",
"label": "rust: cargo test"
},
{
"type": "cargo",
"command": "run",
"group": "build",
"label": "rust: cargo run"
}
]
}
Rust compilation can be resource-intensive. Here's how I manage it:
RAM Usage: With my current settings, rust-analyzer typically uses 2-4GB RAM for large projects. The memoryUsage: "low"
setting helps keep it manageable.
CPU Usage: Compilation benefits from Garuda's performance optimizations. I've set up cargo
to use multiple cores:
# Add to ~/.cargo/config.toml
[build]
jobs = 8 # Adjust based on your CPU cores
SSD Benefits: Rust's incremental compilation really benefits from fast storage. If you're on Garuda with an SSD, you'll notice significantly faster rebuild times.
Sometimes rust-analyzer gets confused. Here's my troubleshooting checklist:
# Restart rust-analyzer
# VS Code Command Palette: "rust-analyzer: Restart server"
# Clear cargo cache
cargo clean
# Update rust-analyzer
rustup component add rust-analyzer --force
# Check rust-analyzer logs in VS Code Output panel
If rust-analyzer is eating too much RAM:
{
"rust-analyzer.memory.useLimit": 4096, // 4GB limit
"rust-analyzer.cargo.loadOutDirsFromCheck": false,
"rust-analyzer.procMacro.enable": false
}
For faster development iterations:
# In Cargo.toml
[profile.dev]
opt-level = 1
debug = true
incremental = true
These show type information inline β incredibly helpful for complex generic code:
{
"rust-analyzer.inlayHints.enable": true,
"rust-analyzer.inlayHints.parameterHints": true,
"rust-analyzer.inlayHints.typeHints": true
}
rust-analyzer's code actions (the lightbulb icon) are fantastic:
This goes beyond syntax highlighting to show semantic meaning:
{
"editor.semanticHighlighting.enabled": true,
"rust-analyzer.highlighting.strings": true
}
GitHub Copilot has been a game-changer for my Rust development. Here's how I've configured it:
{
"github.copilot.enable": {
"rust": true
},
"github.copilot.nextEditSuggestions.enabled": true
}
Copilot is particularly good at:
Since setting up this environment, I've noticed significant improvements:
Faster Development: The combination of auto-save, format-on-save, and instant error checking means I catch issues immediately rather than during compilation.
Better Code Quality: Clippy integration and GitHub Copilot suggestions have improved my Rust idiom usage.
Reduced Context Switching: Everything I need is in one place β debugging, terminal, git, and documentation.
Project Consistency: Using workspace settings ensures all my projects follow the same patterns.
I'm constantly evolving this setup. Some things I'm experimenting with:
WebAssembly Development: Adding wasm-pack integration for projects that compile to WASM.
Cross-compilation: Setting up targets for different platforms directly in VS Code.
Custom Extensions: I'm considering writing a VS Code extension specifically for some of my common Rust workflows.
This setup has been refined through building real projects β from Discord bots to TUI applications to hardware control systems. It's not about having the most extensions or the most complex configuration; it's about having a setup that gets out of your way and lets you focus on solving problems with Rust.
The beauty of this configuration is that it scales well. Whether I'm prototyping a small CLI tool or working on a complex async system like rustycord, the same setup serves me well.
If you're starting your Rust journey or looking to improve your development experience, I'd recommend starting with the basics (rust-analyzer + decent settings) and gradually adding features as you identify pain points in your workflow.
Remember, the best development environment is the one that makes you want to code more. For me, this VS Code setup on Garuda Linux does exactly that β it makes Rust development not just productive, but genuinely enjoyable.
---
Want to see this setup in action? Check out my projects on GitHub or visit my website at iamdhakrey.dev to see what I'm building with this setup.
If you want to replicate this setup quickly:
1. β Install Garuda Linux (GNOME edition recommended) 2. β Install Rust via rustup 3. β Install VS Code 4. β Create a dedicated Rust profile in VS Code 5. β Install the essential extensions listed above 6. β Copy the settings configuration 7. β Set up debugging configuration 8. β Create your first Rust project and start coding!
Happy coding, and may your compile times be short and your memory safety be guaranteed! π¦