diff --git a/frontend/src/components/UserMenu/AccountModal/index.jsx b/frontend/src/components/UserMenu/AccountModal/index.jsx
index 9de868934868591dd62c03aaca9af66fb170a6d3..a77c5145756063a1608409d1d5a105cdfc8de977 100644
--- a/frontend/src/components/UserMenu/AccountModal/index.jsx
+++ b/frontend/src/components/UserMenu/AccountModal/index.jsx
@@ -50,9 +50,9 @@ export default function AccountModal({ user, hideModal }) {
     const { success, error } = await System.updateUser(data);
     if (success) {
       let storedUser = JSON.parse(localStorage.getItem(AUTH_USER));
-
       if (storedUser) {
         storedUser.username = data.username;
+        storedUser.bio = data.bio;
         localStorage.setItem(AUTH_USER, JSON.stringify(storedUser));
       }
       showToast("Profile updated.", "success", { clear: true });
@@ -164,6 +164,20 @@ export default function AccountModal({ user, hideModal }) {
                   Password must be at least 8 characters long
                 </p>
               </div>
+              <div>
+                <label
+                  htmlFor="bio"
+                  className="block mb-2 text-sm font-medium text-white"
+                >
+                  Bio
+                </label>
+                <textarea
+                  name="bio"
+                  className="border-none bg-theme-settings-input-bg placeholder:text-theme-settings-input-placeholder border-gray-500 text-white text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5 min-h-[100px] resize-y"
+                  placeholder="Tell us about yourself..."
+                  defaultValue={user.bio}
+                />
+              </div>
               <div className="flex flex-row gap-x-8">
                 <ThemePreference />
                 <LanguagePreference />
diff --git a/frontend/src/pages/Admin/Users/NewUserModal/index.jsx b/frontend/src/pages/Admin/Users/NewUserModal/index.jsx
index 54dab87ee4d331975388686d76ee07d8605d9dcb..8b11c1a112892e2831787c3835904a55b0283ca2 100644
--- a/frontend/src/pages/Admin/Users/NewUserModal/index.jsx
+++ b/frontend/src/pages/Admin/Users/NewUserModal/index.jsx
@@ -95,6 +95,21 @@ export default function NewUserModal({ closeModal }) {
                   Password must be at least 8 characters long
                 </p>
               </div>
+              <div>
+                <label
+                  htmlFor="bio"
+                  className="block mb-2 text-sm font-medium text-white"
+                >
+                  Bio
+                </label>
+                <textarea
+                  name="bio"
+                  className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
+                  placeholder="User's bio"
+                  autoComplete="off"
+                  rows={3}
+                />
+              </div>
               <div>
                 <label
                   htmlFor="role"
diff --git a/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx b/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx
index 8908b17e644a8ead9f548657dc712f5093fd60f7..5a88e4d898d87144e2dfac28b3c4ae8217fbe43e 100644
--- a/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx
+++ b/frontend/src/pages/Admin/Users/UserRow/EditUserModal/index.jsx
@@ -2,6 +2,7 @@ import React, { useState } from "react";
 import { X } from "@phosphor-icons/react";
 import Admin from "@/models/admin";
 import { MessageLimitInput, RoleHintDisplay } from "../..";
+import { AUTH_USER } from "@/utils/constants";
 
 export default function EditUserModal({ currentUser, user, closeModal }) {
   const [role, setRole] = useState(user.role);
@@ -27,7 +28,17 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
     }
 
     const { success, error } = await Admin.updateUser(user.id, data);
-    if (success) window.location.reload();
+    if (success) {
+      // Update local storage if we're editing our own user
+      if (currentUser && currentUser.id === user.id) {
+        currentUser.username = data.username;
+        currentUser.bio = data.bio;
+        currentUser.role = data.role;
+        localStorage.setItem(AUTH_USER, JSON.stringify(currentUser));
+      }
+
+      window.location.reload();
+    }
     setError(error);
   };
 
@@ -92,6 +103,22 @@ export default function EditUserModal({ currentUser, user, closeModal }) {
                   Password must be at least 8 characters long
                 </p>
               </div>
+              <div>
+                <label
+                  htmlFor="bio"
+                  className="block mb-2 text-sm font-medium text-white"
+                >
+                  Bio
+                </label>
+                <textarea
+                  name="bio"
+                  className="border-none bg-theme-settings-input-bg w-full text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
+                  placeholder="User's bio"
+                  defaultValue={user.bio}
+                  autoComplete="off"
+                  rows={3}
+                />
+              </div>
               <div>
                 <label
                   htmlFor="role"
diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index a11edec62f2416d936209ffd2624c96cf53879aa..8d18772695279a41b942951d513719834d103c13 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -1089,7 +1089,7 @@ function systemEndpoints(app) {
   app.post("/system/user", [validatedRequest], async (request, response) => {
     try {
       const sessionUser = await userFromSession(request, response);
-      const { username, password } = reqBody(request);
+      const { username, password, bio } = reqBody(request);
       const id = Number(sessionUser.id);
 
       if (!id) {
@@ -1098,12 +1098,10 @@ function systemEndpoints(app) {
       }
 
       const updates = {};
-      if (username) {
+      if (username)
         updates.username = User.validations.username(String(username));
-      }
-      if (password) {
-        updates.password = String(password);
-      }
+      if (password) updates.password = String(password);
+      if (bio) updates.bio = String(bio);
 
       if (Object.keys(updates).length === 0) {
         response
diff --git a/server/models/user.js b/server/models/user.js
index e6915d9dcd418533749c74d4ca7fa1031f1a254c..5979de347884762c90cafe2b3451afd3054ee7fe 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -22,6 +22,7 @@ const User = {
     "role",
     "suspended",
     "dailyMessageLimit",
+    "bio",
   ],
   validations: {
     username: (newValue = "") => {
@@ -54,6 +55,12 @@ const User = {
       }
       return limit;
     },
+    bio: (bio = "") => {
+      if (!bio || typeof bio !== "string") return "";
+      if (bio.length > 1000)
+        throw new Error("Bio cannot be longer than 1,000 characters");
+      return String(bio);
+    },
   },
   // validations for the above writable fields.
   castColumnValue: function (key, value) {
@@ -77,6 +84,7 @@ const User = {
     password,
     role = "default",
     dailyMessageLimit = null,
+    bio = "",
   }) {
     const passwordCheck = this.checkPasswordComplexity(password);
     if (!passwordCheck.checkedOK) {
@@ -97,6 +105,7 @@ const User = {
           username: this.validations.username(username),
           password: hashedPassword,
           role: this.validations.role(role),
+          bio: this.validations.bio(bio),
           dailyMessageLimit:
             this.validations.dailyMessageLimit(dailyMessageLimit),
         },
diff --git a/server/prisma/migrations/20250226005538_init/migration.sql b/server/prisma/migrations/20250226005538_init/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4902fbc68595041ad2937988a5c2a1f5a65e465d
--- /dev/null
+++ b/server/prisma/migrations/20250226005538_init/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "users" ADD COLUMN "bio" TEXT DEFAULT '';
diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma
index 37c82d4ddfcf565679df6fd1a5e7a5b6cecda25f..8372d33a4780e6029bed86899dbf9d9c4f4e45d9 100644
--- a/server/prisma/schema.prisma
+++ b/server/prisma/schema.prisma
@@ -68,6 +68,7 @@ model users {
   createdAt                   DateTime                      @default(now())
   lastUpdatedAt               DateTime                      @default(now())
   dailyMessageLimit           Int?
+  bio                         String?                       @default("")
   workspace_chats             workspace_chats[]
   workspace_users             workspace_users[]
   embed_configs               embed_configs[]