uv now has a type-check command. uv check syncs your project environment, downloads the ty type checker and runs it, with no config and no separate pip install. It also checks PEP 723 scripts against their own inline dependencies, which is the part that got me: your type checker has probably been checking those scripts against the wrong venv for years, flagging import requests as unresolved or silently using whatever happened to be installed.
I've been running it and I like it. The "your laptop and CI use the same ty version" pitch needs a footnote, though, and one command fixes it.
I'll go through projects first, then workspaces, scripts, VS Code, pre-commit and GitHub Actions.
What uv check actually does
Per the announcement from October 13, 2026, uv check prepares the project environment, installs its dependencies and checks the project with ty. You need uv 0.12.3 or later and ty 0.0.76 or later. ty itself gets downloaded the first time you run the command, so you don't install it yourself.
It's a preview feature. Astral says so plainly, and if you never run uv check, nothing about your uv workflow changes.
The CLI reference describes it as "Run checks on the project," and adds: "Currently, this type checks Python code using ty." There's also a --fix flag to apply safe fixes. Ruff is on the roadmap but not in the command yet. Frank Chu tested this by adding unused import os and import sys: uv check didn't report either of them. So keep your ruff check step for now.
Step 1: type-check a project with uv check
uv self update # make sure you're on 0.12.3+
uv check
That's the whole setup. On the first run in Chu's test (uv 0.13.5, ty 0.0.91, a 2 vCPU VM), uv created .venv, pulled a managed CPython, built the project and downloaded ty, which was 13.5 MiB. The cold run took 5.53s and warm runs took 0.71s. Bare ty check on the same tiny project took 0.09s, so ty barely registers and most of the time goes to uv syncing the environment.
The exit codes are what CI expects: 1 when there are diagnostics, 0 when the code is clean.
Every run prints an experimental warning. Chu found you can silence it with --preview-features check-command.
Step 2: workspaces with --package and --all-packages
If you use a uv workspace, the flags work the same way they do in uv sync:
uv check --package api # one member: syncs it + its deps, checks only its files
uv check --all-packages # every member in the workspace
The reference docs say --package syncs the workspace environment with the selected members and their dependencies, and "only files owned by those members are checked." In a monorepo, that's what lets you run a quick per-package check in a pre-push hook and the full sweep in CI.
Step 3: check PEP 723 scripts against their own dependencies
This is the part I care about most. Say you have a script like this:
# /// script
# requires-python = ">=3.12"
# dependencies = ["requests"]
# ///
import requests
status: int = requests.get("https://example.com")
Run this:
uv check --script fetch.py
uv builds a separate environment from the script's own metadata and checks the script against it, even when it disagrees with the surrounding project. In Chu's test, plain ty check reported unresolved-import for requests because it was looking in the wrong venv. With the integration, it reported the real bug instead. I ran this exact file with uv 0.13.5, which pulled ty 0.0.92, and got the same thing, exit code 1:
error[invalid-assignment]: Object of type `Response` is not assignable to `int`
--> fetch.py:7:15
uv check on its own doesn't go looking for scripts, though. Chu had to name each one with --script. If you want ty to find and check the project's scripts in one pass, the blog gives an env var:
TY_UV=scripts ty check
That setting is opt-in for a good reason. Astral's explanation: "As dependency installation can require execution of third-party Python code, automatic environment setup is currently opt-in." The same applies to uv check itself, so running uv check on a repo you just cloned is not a read-only operation. Treat it like pip install.
Step 4: ty in VS Code with the uv setting
Install the ty extension, make sure uv is on your PATH, and add this to settings.json:
{
"ty.experimental.useUv": "on"
}
With that set, ty runs uv in the background so completions, hover and Go to Definition inside a script use the script's declared requirements and not your project venv. If you write a lot of throwaway uv run scripts, this alone makes the integration worth trying.
Step 5: the ty pre-commit hook
The ty-pre-commit hook now runs uv check under the hood, and the rev tracks the ty version:
repos:
- repo: https://github.com/astral-sh/ty-pre-commit
rev: v0.0.92 # ty version
hooks:
- id: ty
args: [--isolated]
I'd add --isolated right away. Without it, the hook can create or update your uv.lock and .venv during a commit, which is the kind of side effect that eventually costs you an afternoon. The README also suggests [--isolated, --no-python-downloads, --no-cache] if you want more idempotent runs.
Two other gotchas from the README:
- The hook always checks the whole project. Don't set
pass_filenames: true, because the hook errors if it receives filenames. - It doesn't work on pre-commit.ci, which blocks network access. Add
ci: skip: [ty]there and run the check in your own CI.
Step 6: uv check in GitHub Actions
The ty-pre-commit README uses astral-sh/setup-uv@v10.3.2. Here's a minimal GitHub Actions job built on that:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7.0.1
- uses: astral-sh/setup-uv@v10.3.2
- run: uv check --locked --all-packages
--locked makes the job fail if uv.lock is out of date, so CI can't silently re-resolve and check against different dependencies than the ones you committed.
The catch: uv check only pins ty if you add it
The announcement says uv check "automatically uses the ty version recorded in your project's lockfile," so laptops and CI agree. That only holds once ty is actually in your lockfile.
According to the --ty-version docs, the exact version from uv.lock is used "when ty is a project dependency or a dependency in the project's dev group." If it isn't, uv uses a constrained range like >=0.0,<0.1. ty is at 0.0.9x and ships often, so in that range your laptop and your CI runner can end up on different ty builds, which is exactly the drift the feature is supposed to prevent.
Chu checked this: after uv add --dev "ty==0.0.80", uv check -v used 0.0.80 even though 0.0.91 was out. So the fix is one command:
uv add --dev ty
I did this on a fresh uv init project and uv check -v logged Requirement already installed: ty==0.0.92, the version now in the lockfile.
Do this before you add uv check to CI. I'd argue it should be the default, or at least come with a loud warning.
Should ty replace mypy or Pyright yet?
Not yet, and Astral's post doesn't claim it should. The integration is experimental, ty is still on 0.0.x, and Astral says it is "continuing toward ty's stable release." ty's docs claim it's 10x to 100x faster than mypy and Pyright. I believe the speed claim. What I don't know yet is how many of your existing # type: ignore comments and plugin-dependent patterns (Django, SQLAlchemy, pydantic mypy plugins) will survive the switch.
What I'm doing for now:
| Situation | My call |
|---|---|
| PEP 723 scripts, one-off tools | Use uv check --script now. mypy never handled these well. |
| New project, no mypy plugins | Run uv check in CI next to your current checker for a few weeks |
| Large codebase on mypy plugins | Keep mypy. Try ty in the editor only. |
| Monorepo on uv workspaces | Trial --all-packages in a non-blocking CI job |
Running it next to your current checker costs you about a minute of CI setup. Dropping your current checker for a 0.0.x preview is a bet I'm not making on a production codebase.
So where are you on this? Would you replace mypy or pyright with ty today, or wait until it's out of preview? If you've already switched, tell me which false positives made you want to switch back.
Top comments (1)
I’ve been using uv for my Python projects, and this looks like a useful addition. I like that it handles dependencies and type checking together. The tip about pinning ty before using it in CI is really helpful!