diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9e57dcb0..39ceaa36 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -76,6 +76,9 @@ importers:
       '@fontsource/ibm-plex-mono':
         specifier: ^5.0.13
         version: 5.0.13
+      '@imput/version-info':
+        specifier: workspace:^
+        version: link:../packages/version-info
       '@tabler/icons-svelte':
         specifier: 3.6.0
         version: 3.6.0(svelte@4.2.18)
diff --git a/web/package.json b/web/package.json
index ec3ea3e6..7d486620 100644
--- a/web/package.json
+++ b/web/package.json
@@ -44,6 +44,7 @@
     "dependencies": {
         "@fontsource-variable/noto-sans-mono": "^5.0.20",
         "@fontsource/ibm-plex-mono": "^5.0.13",
+        "@imput/version-info": "workspace:^",
         "@tabler/icons-svelte": "3.6.0",
         "sveltekit-i18n": "^2.4.2",
         "ts-deepmerge": "^7.0.0"
diff --git a/web/src/routes/version.json/+server.ts b/web/src/routes/version.json/+server.ts
index 308fc089..5d77a4ad 100644
--- a/web/src/routes/version.json/+server.ts
+++ b/web/src/routes/version.json/+server.ts
@@ -1,77 +1,5 @@
-import { json }        from '@sveltejs/kit';
-import { readFile }    from 'node:fs/promises';
-import { join, parse } from 'node:path';
-import { existsSync }  from 'node:fs';
-import { cwd }         from 'node:process';
-
-const findFile = (file: string) => {
-    let dir = cwd();
-
-    while (dir !== parse(dir).root) {
-        if (existsSync(join(dir, file))) {
-            return dir;
-        }
-
-        dir = join(dir, '../');
-    }
-}
-
-const root = findFile('.git');
-const pack = findFile('package.json');
-if (!root) {
-    throw 'no git repository root found';
-} else if (!pack) {
-    throw 'no package root found';
-}
-
-const readGit = (filename: string) => readFile(join(root, filename), 'utf8');
-
-const getCommit = async () => {
-    return (await readGit('.git/logs/HEAD'))
-            ?.split('\n')
-            ?.filter(String)
-            ?.pop()
-            ?.split(' ')[1];
-}
-
-const getBranch = async () => {
-    if (process.env.CF_PAGES_BRANCH) {
-        return process.env.CF_PAGES_BRANCH;
-    }
-
-    return (await readGit('.git/HEAD'))
-            ?.replace(/^ref: refs\/heads\//, '')
-            ?.trim();
-}
-
-const getRemote = async () => {
-    let remote = (await readGit('.git/config'))
-                    ?.split('\n')
-                    ?.find(line => line.includes('url = '))
-                    ?.split('url = ')[1];
-
-    if (remote?.startsWith('git@')) {
-        remote = remote.split(':')[1];
-    } else if (remote?.startsWith('http')) {
-        remote = new URL(remote).pathname.substring(1);
-    }
-
-    remote = remote?.replace(/\.git$/, '');
-
-    if (!remote) {
-        throw 'could not parse remote';
-    }
-
-    return remote;
-}
-
-const getVersion = async () => {
-    const { version } = JSON.parse(
-        await readFile(join(pack, 'package.json'), 'utf8')
-    );
-
-    return version;
-}
+import { json } from "@sveltejs/kit";
+import { getCommit, getBranch, getRemote, getVersion } from "@imput/version-info";
 
 export async function GET() {
     return json({
@@ -82,4 +10,4 @@ export async function GET() {
     });
 }
 
-export const prerender = true;
\ No newline at end of file
+export const prerender = true;