Speed up your Python workflow with uv and ruff

June 06, 2025

Recently, I've been exploring ways to make my Python development workflow faster and cleaner and I discovered an incredible duo: uv and ruff. Both are written in Rust and have completely transformed how I work with Python projects. In this blog post, I'll share why I made the switch and how you can easily integrate these tools into your workflow!

Why I started using uv and ruff

Let's be honest — Python tools can be kind of a mess. Between pip, virtualenv, pip-tools, flake8, isort... there's just too much to deal with, and it was honestly getting annoying. Installing packages was slow, and the whole setup started to feel more like a hassle than something helpful.

Then I discovered this Rust-powered combo, and everything changed. Here's what got me hooked:

uv is a super-fast Python package manager that replaces pip, virtualenv and pip-tools - all in one tool. It's modern, reliable, and blazingly fast.

ruff is a lightning-fast linter and formatter that can replace black, flake8, isort and more. One tool to rule them all, basically.

The performance difference is mind-blowing. We're talking about significant speed improvements in package installations and code formatting. Once you experience this speed, there's no going back.

Performance benchmarks

So how fast are we talking, really? Let’s break it down with real benchmarks. From package installs to linting massive codebases, the results are jaw-dropping — and they’re what convinced me to switch for good.

uv delivers remarkable speed gains: According to Astral's official benchmarks, uv is 8-10x faster than pip and pip-tools without caching, but here's where it gets really interesting - with a warm cache (like when you're recreating a virtual environment or updating dependencies), it becomes 80-115x faster. That's not a typo! The speed difference comes from uv's global module cache that avoids re-downloading packages and its use of Copy-on-Write and hardlinks to minimize disk usage.

Even for virtual environment creation, uv is about 80x faster than python -m venv and 7x faster than virtualenv, with no dependency on Python itself.

ruff is equally impressive: The official documentation states that Ruff is 10-100x faster than existing linters like Flake8 and formatters like Black. But what really drives this home are the real-world testimonials from developers who've made the switch.

Bryan Van de Ven — co-creator of Bokeh and original author of Conda — shared a great comparison:

“Ruff is ~150–200x faster than flake8 on my machine. Scanning the whole repo takes ~0.2s instead of ~20s.”

Nick Schrock, founder of Elementl and co-creator of GraphQL, also reported impressive results:

“On our largest module (Dagster itself, 250k LOC), pylint takes about 2.5 minutes, parallelized across 4 cores on my M1. Running Ruff against our entire codebase takes 0.4 seconds.”

References:

  1. uv: Python packaging in Rust - Astral Official Blog
  2. Ruff Official Documentation
  3. uv Benchmarks Documentation
  4. Trunk Performance Comparison

How easy these tools are to use

Here's the best part - these tools are designed to be drop-in replacements. You don't need to rewrite your entire workflow or learn completely new concepts. Just swap out the tools and enjoy the speed boost!

Both uv and ruff work with your existing Python projects and configurations. They respect your current setup while making everything faster and more reliable.

Quick tutorial and example

Let me show you how simple it is to get started with both tools.

Installing uv and ruff

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh # On Windows: powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Install ruff
pip install ruff

Creating a new project with uv

Starting a new project is incredibly straightforward:

# Create and activate virtual environment
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Initialize project (creates pyproject.toml)
uv init

# Install packages (lightning fast!)
uv pip add requests pandas fastapi

That's it! You now have a .venv managed by uv, packages install incredibly fast, and you get a uv.lock file for perfect reproducibility.

Setting up ruff

The beauty of ruff is that it works great out of the box with zero configuration. You can start using it immediately:

# Check for issues in your codebase
ruff check .

# Auto-fix what can be fixed automatically
ruff check . --fix

# Format your code
ruff format .

If you'd like to customize ruff's behavior, you can configure it via a pyproject.toml, ruff.toml or .ruff.toml file. It looks for the closest configuration file in the directory hierarchy and applies its settings.

Here’s a simple configuration example using pyproject.toml:

[tool.ruff]
# Set the maximum line length
line-length = 88

# Assume Python 3.12
target-version = "py312"

You can explore all available settings in the ruff settings documentation. For a deeper look at how to configure ruff, check out the configuration guide.

This setup gives you a powerful and streamlined workflow by combining the functionality of tools like black, isort, flake8, and several plugins — all in a single, blazing-fast tool.

My production setup with pre-commits and github workflows

In my workflow, I use ruff with pre-commit hooks to automatically check for linting and formatting errors before each commit. I also have GitHub workflows set up to ensure code quality in my repositories. Additionally, I use uv to improve build times across my CI/CD pipelines. I might dive deeper into pre-commit setup and uv use cases in a future post, but here's the GitHub workflow I use:

name: Ruff

on: [pull_request]

jobs:
  ruff-lint:
    name: Ruff Linter
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Ruff linter
        uses: astral-sh/ruff-action@v3
        with:
          args: check .

  ruff-format:
    name: Ruff Formatter
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Ruff formatter check
        uses: astral-sh/ruff-action@v3
        with:
          args: format --check --diff

This workflow runs on every pull request and checks both linting and formatting. It's simple, fast and catches issues before they make it into the main branch.

Conclusion

This combo has made my Python workflow smoother and way faster. The best part is that you don't need to change everything at once. You can start by replacing your current linter/formatter with ruff, then try uv for new projects to see the speed difference.

Let me know if you try this out or have other tools that are game-changers for your setup!

print("See ya 😎")

Profile picture

Written by Mateus Elias using Gatsby, to share tech knowledge and personal experiences! You should follow him on GitHub.