diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
index 87fd55587..c4062102e 100644
--- a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
+++ b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/ThreadItem/index.jsx
@@ -27,7 +27,6 @@ export default function ThreadItem({
   const { slug } = useParams();
   const optionsContainer = useRef(null);
   const [showOptions, setShowOptions] = useState(false);
-  const [name, setName] = useState(thread.name);
   const linkTo = !thread.slug
     ? paths.workspace.chat(slug)
     : paths.workspace.thread(slug, thread.slug);
@@ -97,7 +96,7 @@ export default function ThreadItem({
                 isActive ? "font-medium text-white" : "text-slate-400"
               }`}
             >
-              {truncate(name, 25)}
+              {truncate(thread.name, 25)}
             </p>
           </a>
         )}
@@ -133,7 +132,6 @@ export default function ThreadItem({
                 workspace={workspace}
                 thread={thread}
                 onRemove={onRemove}
-                onRename={setName}
                 close={() => setShowOptions(false)}
               />
             )}
@@ -144,14 +142,7 @@ export default function ThreadItem({
   );
 }
 
-function OptionsMenu({
-  containerRef,
-  workspace,
-  thread,
-  onRename,
-  onRemove,
-  close,
-}) {
+function OptionsMenu({ containerRef, workspace, thread, onRemove, close }) {
   const menuRef = useRef(null);
 
   // Ref menu options
@@ -208,7 +199,7 @@ function OptionsMenu({
       return;
     }
 
-    onRename(name);
+    thread.name = name;
     close();
   };
 
diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
index d1c0ba8c2..f2d99cd87 100644
--- a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
+++ b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx
@@ -12,6 +12,26 @@ export default function ThreadContainer({ workspace }) {
   const [loading, setLoading] = useState(true);
   const [ctrlPressed, setCtrlPressed] = useState(false);
 
+  useEffect(() => {
+    const chatHandler = (event) => {
+      const { threadSlug, newName } = event.detail;
+      setThreads((prevThreads) =>
+        prevThreads.map((thread) => {
+          if (thread.slug === threadSlug) {
+            return { ...thread, name: newName };
+          }
+          return thread;
+        })
+      );
+    };
+
+    window.addEventListener("renameThread", chatHandler);
+
+    return () => {
+      window.removeEventListener("renameThread", chatHandler);
+    };
+  }, []);
+
   useEffect(() => {
     async function fetchThreads() {
       if (!workspace.slug) return;
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx
index 28d87e0df..6e32d23f8 100644
--- a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx
+++ b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx
@@ -12,6 +12,7 @@ import handleSocketResponse, {
   AGENT_SESSION_END,
   AGENT_SESSION_START,
 } from "@/utils/chat/agent";
+import truncate from "truncate";
 
 export default function ChatContainer({ workspace, knownHistory = [] }) {
   const { threadSlug = null } = useParams();
@@ -39,6 +40,18 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
     event.preventDefault();
     if (!message || message === "") return false;
 
+    // If first message and it is a thread
+    // and message is not blank/whitespace,
+    // then send event to rename the thread
+    if (threadSlug && chatHistory.length === 0 && message.trim().length > 0) {
+      const truncatedName = truncate(message, 22);
+      window.dispatchEvent(
+        new CustomEvent("renameThread", {
+          detail: { threadSlug, newName: truncatedName },
+        })
+      );
+    }
+
     const prevChatHistory = [
       ...chatHistory,
       { content: message, role: "user" },
diff --git a/server/endpoints/chat.js b/server/endpoints/chat.js
index 7445c2134..915acbf95 100644
--- a/server/endpoints/chat.js
+++ b/server/endpoints/chat.js
@@ -15,6 +15,8 @@ const {
   validWorkspaceSlug,
 } = require("../utils/middleware/validWorkspace");
 const { writeResponseChunk } = require("../utils/helpers/chat/responses");
+const { WorkspaceThread } = require("../models/workspaceThread");
+const truncate = require("truncate");
 
 function chatEndpoints(app) {
   if (!app) return;
@@ -196,6 +198,14 @@ function chatEndpoints(app) {
           user,
           thread
         );
+
+        await WorkspaceThread.autoRenameThread({
+          thread,
+          workspace,
+          user,
+          newName: truncate(message, 22),
+        });
+
         await Telemetry.sendTelemetry("sent_chat", {
           multiUserMode: multiUserMode(response),
           LLMSelection: process.env.LLM_PROVIDER || "openai",
diff --git a/server/models/workspaceThread.js b/server/models/workspaceThread.js
index a2a96f310..ffbc8aedb 100644
--- a/server/models/workspaceThread.js
+++ b/server/models/workspaceThread.js
@@ -8,7 +8,7 @@ const WorkspaceThread = {
     try {
       const thread = await prisma.workspace_threads.create({
         data: {
-          name: "New thread",
+          name: "Thread",
           slug: uuidv4(),
           user_id: userId ? Number(userId) : null,
           workspace_id: workspace.id,
@@ -84,6 +84,25 @@ const WorkspaceThread = {
       return [];
     }
   },
+
+  // Will fire on first message (included or not) for a thread and rename the thread with the newName prop.
+  autoRenameThread: async function ({
+    workspace = null,
+    thread = null,
+    user = null,
+    newName = null,
+  }) {
+    if (!workspace || !thread || !newName) return false;
+    const { WorkspaceChats } = require("./workspaceChats");
+    const chatCount = await WorkspaceChats.count({
+      workspaceId: workspace.id,
+      user_id: user?.id || null,
+      thread_id: thread.id,
+    });
+    if (chatCount !== 1) return false;
+    await this.update(thread, { name: newName });
+    return true;
+  },
 };
 
 module.exports = { WorkspaceThread };
diff --git a/server/package.json b/server/package.json
index 1b0ba2802..9cc27c8b0 100644
--- a/server/package.json
+++ b/server/package.json
@@ -75,6 +75,7 @@
     "sqlite3": "^5.1.6",
     "swagger-autogen": "^2.23.5",
     "swagger-ui-express": "^5.0.0",
+    "truncate": "^3.0.0",
     "url-pattern": "^1.0.3",
     "uuid": "^9.0.0",
     "uuid-apikey": "^1.5.3",
diff --git a/server/yarn.lock b/server/yarn.lock
index c6cf4c2c3..a05c62fc4 100644
--- a/server/yarn.lock
+++ b/server/yarn.lock
@@ -6211,6 +6211,11 @@ triple-beam@^1.3.0:
   resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984"
   integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==
 
+truncate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/truncate/-/truncate-3.0.0.tgz#7dbe19e2f72c614e36b79bab00fbfbeb1cbaf078"
+  integrity sha512-C+0Xojw7wZPl6MDq5UjMTuxZvBPK04mtdFet7k+GSZPINcvLZFCXg+15kWIL4wAqDB7CksIsKiRLbQ1wa7rKdw==
+
 tslib@^2.2.0, tslib@^2.4.0, tslib@^2.5.3, tslib@^2.6.2:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"