ty
5 min read
Extremely fast Python type checker and language server by Astral (creators of uv and Ruff). Written in Rust. 10–80x faster than mypy and Pyright.
Status: Beta (released December 2025, formerly "Red Knot"). Stable 1.0 targeted for 2026. Expect bugs and missing features. Playground: https://play.ty.dev
Install
sh
# Run without installing
uvx ty check
# Project dev dependency (recommended)
uv add --dev ty
uv run ty check
# Global via uv tool
uv tool install ty@latest
# Standalone installer
curl -LsSf https://astral.sh/ty/install.sh | sh
# pip / pipx
pip install ty
pipx install ty
# mise
mise install ty && mise use --global ty
# Docker
COPY --from=ghcr.io/astral-sh/ty:latest /ty /bin/
# Shell completions
ty generate-shell-completion bash|zsh|fish|elvish|powershell
CLI
ty check [PATHS]
Check files or directories for type errors. Defaults to the project root.
sh
ty check src/
ty check --watch # recheck on file changes
ty check --python .venv # use specific virtualenv
ty check --python-version 3.12
ty check --output-format github # CI annotation format
ty check --add-ignore # auto-add ty: ignore to all current diagnostics
| Flag | Description |
|---|---|
--watch / -W | Recheck on file change |
--python PATH | Python interpreter or venv |
--python-version | Target version (3.7–3.15, default 3.14) |
--python-platform | win32 | darwin | linux | android | ios | all |
--output-format | full | concise | gitlab | github | junit |
--error RULE | Treat rule as error (use all for every rule) |
--warn RULE | Treat rule as warning |
--ignore RULE | Disable rule |
--add-ignore | Insert ty: ignore comments for all current diagnostics |
--fix | Apply auto-fixes |
--error-on-warning | Exit 1 on any warning |
--exit-zero | Always exit 0 |
--extra-search-path PATH | Extra module resolution path |
--typeshed PATH | Custom typeshed directory |
--exclude PATTERN | Gitignore-style exclusion |
-c KEY=VALUE | Override a config key inline |
--config-file PATH | Explicit config file |
--project DIR | Run within given project directory |
Other Commands
sh
ty server # start LSP language server
ty explain [RULE] # explain a rule or list all rules
ty version # show version
ty help # help
Configuration
Config is discovered by walking up from the current directory. ty.toml takes precedence over pyproject.toml when both exist.
User-level config:
• macOS/Linux: ~/.config/ty/ty.toml
• Windows: %APPDATA%\ty\ty.toml
pyproject.toml
toml
[tool.ty.environment]
python-version = "3.12"
python-platform = "linux"
python = ".venv"
extra-paths = ["src/stubs"]
typeshed = "/path/to/custom/typeshed"
[tool.ty.src]
include = ["src", "tests"]
exclude = ["tests/fixtures"]
respect-ignore-files = true
[tool.ty.rules]
division-by-zero = "warn"
unused-ignore-comment = "error"
unresolved-import = "warn"
[tool.ty.analysis]
allowed-unresolved-imports = ["mypy_extensions.*", "some_untyped_lib.*"]
replace-imports-with-any = ["some_dynamic_lib.*"]
respect-type-ignore-comments = true # default true
[tool.ty.terminal]
output-format = "full"
error-on-warning = false
# Per-file overrides
[[tool.ty.overrides]]
include = ["tests/**"]
rules = { invalid-return-type = "ignore" }
[[tool.ty.overrides]]
include = ["src/legacy/**"]
rules = { all = "ignore" }
ty.toml (same keys, no [tool.ty] prefix)
toml
[rules]
division-by-zero = "warn"
[environment]
python-version = "3.12"
[src]
include = ["src"]
Rules
Severity levels: error | warn | ignore. Configure in [tool.ty.rules] or per-file in [[overrides]].
List all rules and their descriptions:
sh
ty explain rule
ty explain rule unresolved-import
Common Rules
| Rule | Default | Description |
|---|---|---|
unresolved-import | error | Failed import |
unresolved-attribute | error | Attribute not found on object |
unresolved-reference | error | Reference to undefined name |
invalid-argument-type | error | Argument not assignable to parameter |
invalid-return-type | error | Return value incompatible with annotation |
invalid-assignment | error | Assignment violating type rules |
missing-argument | error | Missing required argument |
too-many-positional-arguments | error | Excess positional arguments |
unknown-argument | error | Unknown keyword argument |
call-non-callable | error | Calling a non-callable |
not-iterable | error | Iterating over non-iterable |
not-subscriptable | error | Subscripting non-subscriptable |
unsupported-operator | error | Operator on incompatible types |
index-out-of-bounds | error | Out-of-bounds index access |
possibly-unresolved-reference | error | Potentially undefined name |
invalid-overload | error | Invalid @overload usage |
no-matching-overload | error | Call matches no overload |
invalid-type-arguments | error | Invalid generic type arguments |
type-assertion-failure | error | Failed assert_type() |
unused-awaitable | error | Unused awaitable |
unused-ignore-comment | error | Unnecessary ty: ignore comment |
unused-type-ignore-comment | error | Unnecessary type: ignore comment |
invalid-raise | error | Invalid raise statement |
invalid-exception-caught | error | Handler catching non-exception |
subclass-of-final-class | error | Inheriting from @final class |
override-of-final-method | error | Overriding @final method |
division-by-zero | ignore | Literal division by zero (opt-in) |
deprecated | warn | Use of deprecated items |
invalid-ignore-comment | warn | Malformed ignore comment |
ignore-comment-unknown-rule | warn | ty: ignore[bad-code] |
Suppressing Diagnostics
Inline
python
x = 20 / 0 # ty: ignore[division-by-zero]
x = 20 / 0 # ty: ignore # suppress all on this line
# Standard mypy syntax also works
x = 20 / 0 # type: ignore[ty:division-by-zero]
Unknown rule codes in ty: ignore[...] raise ignore-comment-unknown-rule.
Auto-suppress all current diagnostics
sh
ty check --add-ignore
Config (disable globally or per-file)
toml
[tool.ty.rules]
division-by-zero = "ignore"
[[tool.ty.overrides]]
include = ["tests/**"]
rules = { invalid-return-type = "ignore" }
CLI
sh
ty check --ignore division-by-zero
ty check --warn unresolved-import --error deprecated
Language Server
sh
ty server # starts LSP on stdin/stdout
Features: go to definition, rename, auto-complete, auto-import, semantic highlighting, inlay hints, code actions, fine-grained incremental analysis, Jupyter notebook cross-cell analysis.
Editor Integrations
VS Code
Install the official ty extension (published by Astral). It automatically disables Pylance's type checking.
To keep Pylance for completions but use ty for type checking only:
json
{
"python.languageServer": "Pylance",
"ty.disableLanguageServices": true
}
Neovim
Neovim ≥ 0.11:
lua
vim.lsp.config('ty', { settings = { ty = {} } })
vim.lsp.enable('ty')
Neovim < 0.11 (via nvim-lspconfig):
lua
require('lspconfig').ty.setup({ settings = { ty = {} } })
Zed
Built-in support. Enable in settings.json:
json
{
"languages": {
"Python": {
"language_servers": ["ty", "ruff"]
}
}
}
Override binary path:
json
{
"lsp": {
"ty": {
"binary": { "path": "/home/user/.local/bin/ty", "arguments": ["server"] }
}
}
}
PyCharm
Native support from PyCharm 2025.3+. Settings → Python | Tools | ty → Enable.
Emacs (Eglot)
elisp
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs
'(python-base-mode . ("ty" "server"))))
(add-hook 'python-base-mode-hook 'eglot-ensure)
Comparison with mypy / Pyright
| Aspect | ty | mypy | Pyright |
|---|---|---|---|
| Speed | 10–80x faster | baseline | baseline |
| Implementation | Rust | Python | TypeScript |
| Spec conformance | ~53% (beta) | ~58% | ~98% |
| Checks unannotated bodies | Yes (default) | No (opt-in) | Optional |
| Plugin system | No (roadmap) | Yes | No |
| Pydantic/Django | Beta gaps | Via plugins | Partial |
| Language server | Built-in | Via pylsp-mypy | Pylance/pyright |
| Pre-release | Beta | Stable | Stable |
Performance examples: home-assistant — ty 2.19s vs mypy 45.66s (20x). PyTorch incremental edit — ty 4.7ms vs Pyright 386ms (80x).
ty checks all code including unannotated function bodies (mypy skips them by default). ty guarantees the "gradual guarantee": adding annotations to passing code never introduces new errors.