diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5d6c5953507912fc11242a9a32e3384a4de5029d
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,102 @@
+# SPDX-FileCopyrightText: OpenTalk GmbH <mail@opentalk.eu>
+#
+# SPDX-License-Identifier: EUPL-1.2
+
+---
+# For setup instructions see the backend onboarding doc.
+# https://git.opentalk.dev/a.weiche/the-knowledge/-/blob/main/backend-onboarding.md?ref_type=heads#pre-commit
+exclude: target/|.*\.snap|.*.sql
+
+repos:
+  # These are "general" hooks provided by the pre-commit devs
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v3.2.0
+    hooks:
+      - id: trailing-whitespace
+      - id: end-of-file-fixer
+      - id: check-added-large-files
+  # A repo containing hooks for certain cargo subcommands
+  # Used for tools that don't bring official hooks
+  # Maybe we should create such a "dummy" project ourselves
+  - repo: https://github.com/AndrejOrsula/pre-commit-cargo
+    rev: 0.4.0
+    hooks:
+      - id: cargo-fmt
+      - id: cargo-clippy
+        name: cargo clippy pedantic
+        args:
+          - --all-features
+          - --
+          - --deny
+          - warnings
+          - --deny
+          - clippy::pedantic
+          - --allow
+          - clippy::cast-possible-truncation
+          - --allow
+          - clippy::cast-possible-wrap
+          - --allow
+          - clippy::cast-precision-loss
+          - --allow
+          - clippy::cast-sign-loss
+          - --allow
+          - clippy::doc-markdown
+      - id: cargo-clippy
+        name: cargo clippy tests
+        args:
+          - --all-features
+          - --tests
+          - --
+          - --deny
+          - warnings
+          - --deny
+          - clippy::all
+      - id: cargo-doc
+        args:
+          - --workspace
+          - --no-deps
+  - repo: https://github.com/EmbarkStudios/cargo-deny
+    rev: 0.18.2
+    hooks:
+      - id: cargo-deny
+        args:
+          - --all-features
+          - --workspace
+          - check
+          - --deny
+          - unmatched-skip
+          - --deny
+          - license-not-encountered
+          - --deny
+          - advisory-not-detected
+  # There currently is no official taplo hook, but this one got recommended in the corresponding issue
+  - repo: https://github.com/ComPWA/taplo-pre-commit
+    rev: v0.9.3
+    hooks:
+      - id: taplo-format
+      - id: taplo-lint
+  - repo: https://github.com/adrienverge/yamllint.git
+    rev: v1.29.0
+    hooks:
+      - id: yamllint
+        exclude: ^api/docs/openapi\.yml$
+        args:
+          - .
+  - repo: https://github.com/fsfe/reuse-tool
+    rev: v5.0.2
+    hooks:
+      - id: reuse-lint-file
+  - repo: https://github.com/markdownlint/markdownlint
+    rev: v0.13.0
+    hooks:
+      - id: markdownlint
+        args:
+          - --style
+          - .markdown_style.rb
+          - --warnings
+  # No official hooks for commitlint available, this one seems actively maintained
+  - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
+    rev: v9.22.0
+    hooks:
+      - id: commitlint
+        stages: [commit-msg]
diff --git a/deny.toml b/deny.toml
index 0e7ac55438c5929f75e7a4a4517fa64c91df4b0c..737e86720108b34b1e019502399a4ac67f544485 100644
--- a/deny.toml
+++ b/deny.toml
@@ -45,7 +45,7 @@ ignore = [
   # This is an advisory for the 'paste' crate, which is no longer maintained
   # Since this is a dependency for gstreamer, we can't really do anything
   # against it, but wait for a new gstreamer release.
-  "RUSTSEC-2024-0436"
+  "RUSTSEC-2024-0436",
 ]
 # Threshold for security vulnerabilities, any vulnerability with a CVSS score
 # lower than the range specified will be ignored. Note that ignored advisories