diff --git a/days/5/main.ts b/days/5/main.ts
new file mode 100644
index 0000000..a2cb56c
--- /dev/null
+++ b/days/5/main.ts
@@ -0,0 +1,70 @@
+import { loadInput } from "utils";
+
+export function part1(input: Array<string>) {
+  const { rules, updates } = parseInput(input);
+  const graph = buildDependencyGraph(rules);
+  return updates.filter((update) => isUpdateOrderValid(update, graph)).reduce(
+    (acc, update) => acc + update[Math.floor(update.length / 2)],
+    0,
+  );
+}
+
+export function part2(input: Array<string>) {
+  const { rules, updates } = parseInput(input);
+  const graph = buildDependencyGraph(rules);
+  return updates.filter((update) => !isUpdateOrderValid(update, graph))
+    .map((update) => orderUpdateCorrectly(update, graph)).reduce(
+      (acc, update) => acc + update[Math.floor(update.length / 2)],
+      0,
+    );
+}
+
+function isUpdateOrderValid(update: Array<number>, graph: DependencyGraph) {
+  const visited = new Set<number>();
+  for (const page of update) {
+    const dependencies = graph.get(page) ?? [];
+    for (const dependency of dependencies) {
+      if (update.includes(dependency) && !visited.has(dependency)) {
+        return false;
+      }
+    }
+    visited.add(page);
+  }
+  return true;
+}
+
+function orderUpdateCorrectly(update: Array<number>, graph: DependencyGraph) {
+  function compare(a: number, b: number) {
+    return update.includes(b) && graph.get(a)?.has(b) ? 1 : -1;
+  }
+  return update.toSorted(compare);
+}
+
+type DependencyGraph = Map<number, Set<number>>;
+function buildDependencyGraph(rules: Array<[number, number]>): DependencyGraph {
+  const graph = new Map<number, Set<number>>();
+  for (const [predecessor, dependent] of rules) {
+    const set = graph.get(dependent) ?? new Set<number>();
+    set.add(predecessor);
+    graph.set(dependent, set);
+  }
+  return graph;
+}
+
+function parseInput(input: Array<string>) {
+  const rules: Array<[number, number]> = [];
+  const updates: Array<Array<number>> = [];
+  const split = input.indexOf("");
+  for (let i = 0; i < split; i++) {
+    rules.push(input[i].split("|").map(Number) as [number, number]);
+  }
+  for (let i = split + 1; i < input.length; i++) {
+    updates.push(input[i].split(",").map(Number));
+  }
+  return { rules, updates };
+}
+
+if (import.meta.main) {
+  console.log(part1(await loadInput(5)));
+  console.log(part2(await loadInput(5)));
+}
diff --git a/days/5/main_test.ts b/days/5/main_test.ts
new file mode 100644
index 0000000..983cbac
--- /dev/null
+++ b/days/5/main_test.ts
@@ -0,0 +1,55 @@
+import { expect } from "@std/expect";
+import { describe, it } from "@std/testing/bdd";
+import { part1, part2 } from "./main.ts";
+import { loadInput } from "utils";
+
+const input = [
+  "47|53",
+  "97|13",
+  "97|61",
+  "97|47",
+  "75|29",
+  "61|13",
+  "75|53",
+  "29|13",
+  "97|29",
+  "53|29",
+  "61|53",
+  "97|53",
+  "61|29",
+  "47|13",
+  "75|47",
+  "97|75",
+  "47|61",
+  "75|61",
+  "47|29",
+  "75|13",
+  "53|13",
+  "",
+  "75,47,61,53,29",
+  "97,61,53,29,13",
+  "75,29,13",
+  "75,97,47,61,53",
+  "61,13,29",
+  "97,13,75,29,47",
+];
+
+describe("day 5 example", () => {
+  it("part 1", () => {
+    expect(part1(input)).toBe(143);
+  });
+
+  it("part 2", () => {
+    expect(part2(input)).toBe(123);
+  });
+});
+
+describe("day 5 solution", () => {
+  it("part 1", async () => {
+    expect(part1(await loadInput(5))).toBe(4774);
+  });
+
+  it("part 2", async () => {
+    expect(part2(await loadInput(5))).toBe(6004);
+  });
+});
diff --git a/days/mod.ts b/days/mod.ts
index 83bca74..f03463a 100644
--- a/days/mod.ts
+++ b/days/mod.ts
@@ -3,7 +3,7 @@ type Solution = { part1: PartFunction; part2: PartFunction };
 
 const days = new Map<number, Solution>();
 
-for (const day of [1, 2, 3, 4]) {
+for (const day of [1, 2, 3, 4, 5]) {
   days.set(day, await import(`./${day}/main.ts`));
 }
 
diff --git a/inputs b/inputs
index 3d73dec..a5017e7 160000
--- a/inputs
+++ b/inputs
@@ -1 +1 @@
-Subproject commit 3d73deca6532057d783f9a68744601823c1437c1
+Subproject commit a5017e70038bc89d7bd766fb9cb59bca8662a273