diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bf895f2d642f1a83d19095d762e0b2584d5f158f..0103828ac43b0ea62c2e546d339b73605c1cfdac 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -80,6 +80,14 @@ pre-commit:hooks:
     - pre-commit run -a insert-license
     - pre-commit run -a mdformat
 
+ruff:
+  extends:
+    - .code_changes
+    - .pre-commit
+  stage: checks
+  script:
+    - pre-commit run -a ruff
+
 .tests:
   extends: .changes
   stage: tests
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a773956b4a6447c132e7e01d9d483cc259398b6a..5c6a040d497154d22c33f48c2866683a5e16d71c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,6 +10,11 @@ repos:
       - id: end-of-file-fixer
       - id: mixed-line-ending
       - id: trailing-whitespace
+- repo: https://github.com/charliermarsh/ruff-pre-commit
+  rev: v0.0.254
+  hooks:
+    - id: ruff
+      args: [--fix, --exit-non-zero-on-fix]
 -   repo: https://github.com/psf/black
     rev: 23.1.0
     hooks:
diff --git a/pyproject.toml b/pyproject.toml
index 23e2a26302bf8178bb60e7dc1e7692bf99f36662..0cefdc0675dd93a0bff22776addb6c9ccbabd2e1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -43,3 +43,10 @@ classifiers = [
 
 [tool.mypy]
 ignore_missing_imports = true
+
+[tool.ruff]
+line-length = 101
+target-version = "py37"
+select = ["W", "I", "UP", "YTT", "B", "A", "DTZ", "T10",
+"EXE", "ISC", "ICN", "G", "INP", "PIE", "PYI", "Q", "RSE", "SLF", "TID",
+"COM", "C4", "PT", "RET", "SIM", "PTH", "PGH", "PL", "TRY", "RUF"]