diff --git a/templates/components/engines/typescript/agent/tools/interpreter.ts b/templates/components/engines/typescript/agent/tools/interpreter.ts
index d34aa6c167bca6a3a677ca3f57a06fac50de9150..cad7a0a0f474bd001fe3d732a4327435b98a6a3c 100644
--- a/templates/components/engines/typescript/agent/tools/interpreter.ts
+++ b/templates/components/engines/typescript/agent/tools/interpreter.ts
@@ -15,7 +15,7 @@ export type InterpreterToolParams = {
   fileServerURLPrefix?: string;
 };
 
-export type InterpreterToolOuput = {
+export type InterpreterToolOutput = {
   isError: boolean;
   logs: Logs;
   extraResult: InterpreterExtraResult[];
@@ -88,7 +88,7 @@ export class InterpreterTool implements BaseTool<InterpreterParameter> {
     return this.codeInterpreter;
   }
 
-  public async codeInterpret(code: string): Promise<InterpreterToolOuput> {
+  public async codeInterpret(code: string): Promise<InterpreterToolOutput> {
     console.log(
       `\n${"=".repeat(50)}\n> Running following AI-generated code:\n${code}\n${"=".repeat(50)}`,
     );
@@ -96,7 +96,7 @@ export class InterpreterTool implements BaseTool<InterpreterParameter> {
     const exec = await interpreter.notebook.execCell(code);
     if (exec.error) console.error("[Code Interpreter error]", exec.error);
     const extraResult = await this.getExtraResult(exec.results[0]);
-    const result: InterpreterToolOuput = {
+    const result: InterpreterToolOutput = {
       isError: !!exec.error,
       logs: exec.logs,
       extraResult,
@@ -104,7 +104,7 @@ export class InterpreterTool implements BaseTool<InterpreterParameter> {
     return result;
   }
 
-  async call(input: InterpreterParameter): Promise<InterpreterToolOuput> {
+  async call(input: InterpreterParameter): Promise<InterpreterToolOutput> {
     const result = await this.codeInterpret(input.code);
     await this.codeInterpreter?.close();
     return result;
diff --git a/templates/types/streaming/express/src/controllers/stream-helper.ts b/templates/types/streaming/express/src/controllers/stream-helper.ts
index 9f1a8864bfa63e06e8e622a641075cd34ac604d8..ffc5dfc58c8e6fb0d705f05b2689bf02609a6970 100644
--- a/templates/types/streaming/express/src/controllers/stream-helper.ts
+++ b/templates/types/streaming/express/src/controllers/stream-helper.ts
@@ -17,6 +17,22 @@ export function appendImageData(data: StreamData, imageUrl?: string) {
   });
 }
 
+function getNodeUrl(metadata: Metadata) {
+  const url = metadata["URL"];
+  if (url) return url;
+  const fileName = metadata["file_name"];
+  if (!process.env.FILESERVER_URL_PREFIX) {
+    console.warn(
+      "FILESERVER_URL_PREFIX is not set. File URLs will not be generated.",
+    );
+    return undefined;
+  }
+  if (fileName) {
+    return `${process.env.FILESERVER_URL_PREFIX}/data/${fileName}`;
+  }
+  return undefined;
+}
+
 export function appendSourceData(
   data: StreamData,
   sourceNodes?: NodeWithScore<Metadata>[],
@@ -29,6 +45,7 @@ export function appendSourceData(
         ...node.node.toMutableJSON(),
         id: node.node.id_,
         score: node.score ?? null,
+        url: getNodeUrl(node.node.metadata),
       })),
     },
   });
diff --git a/templates/types/streaming/fastapi/app/api/routers/chat.py b/templates/types/streaming/fastapi/app/api/routers/chat.py
index a23cc44096c8f1b277cd2dddc4ab5035511512d2..aad9f6e8ffb2e9861c7cc2ddfca3942dbbef88c8 100644
--- a/templates/types/streaming/fastapi/app/api/routers/chat.py
+++ b/templates/types/streaming/fastapi/app/api/routers/chat.py
@@ -1,3 +1,5 @@
+import os
+import logging
 from pydantic import BaseModel
 from typing import List, Any, Optional, Dict, Tuple
 from fastapi import APIRouter, Depends, HTTPException, Request, status
@@ -11,6 +13,7 @@ from aiostream import stream
 
 chat_router = r = APIRouter()
 
+logger = logging.getLogger("uvicorn")
 
 class _Message(BaseModel):
     role: MessageRole
@@ -38,14 +41,27 @@ class _SourceNodes(BaseModel):
     metadata: Dict[str, Any]
     score: Optional[float]
     text: str
+    url: Optional[str]
 
     @classmethod
     def from_source_node(cls, source_node: NodeWithScore):
+        metadata = source_node.node.metadata
+        url = metadata.get("URL")
+        
+        if not url:
+            file_name = metadata.get("file_name")
+            url_prefix = os.getenv("FILESERVER_URL_PREFIX")
+            if not url_prefix:
+                logger.warning("Warning: FILESERVER_URL_PREFIX not set in environment variables")
+            if file_name and url_prefix:
+                url = f"{url_prefix}/data/{file_name}"
+
         return cls(
             id=source_node.node.node_id,
-            metadata=source_node.node.metadata,
+            metadata=metadata,
             score=source_node.score,
             text=source_node.node.text,  # type: ignore
+            url=url
         )
 
     @classmethod
diff --git a/templates/types/streaming/nextjs/app/api/chat/stream-helper.ts b/templates/types/streaming/nextjs/app/api/chat/stream-helper.ts
index 9f1a8864bfa63e06e8e622a641075cd34ac604d8..ffc5dfc58c8e6fb0d705f05b2689bf02609a6970 100644
--- a/templates/types/streaming/nextjs/app/api/chat/stream-helper.ts
+++ b/templates/types/streaming/nextjs/app/api/chat/stream-helper.ts
@@ -17,6 +17,22 @@ export function appendImageData(data: StreamData, imageUrl?: string) {
   });
 }
 
+function getNodeUrl(metadata: Metadata) {
+  const url = metadata["URL"];
+  if (url) return url;
+  const fileName = metadata["file_name"];
+  if (!process.env.FILESERVER_URL_PREFIX) {
+    console.warn(
+      "FILESERVER_URL_PREFIX is not set. File URLs will not be generated.",
+    );
+    return undefined;
+  }
+  if (fileName) {
+    return `${process.env.FILESERVER_URL_PREFIX}/data/${fileName}`;
+  }
+  return undefined;
+}
+
 export function appendSourceData(
   data: StreamData,
   sourceNodes?: NodeWithScore<Metadata>[],
@@ -29,6 +45,7 @@ export function appendSourceData(
         ...node.node.toMutableJSON(),
         id: node.node.id_,
         score: node.score ?? null,
+        url: getNodeUrl(node.node.metadata),
       })),
     },
   });
diff --git a/templates/types/streaming/nextjs/app/components/ui/chat/chat-sources.tsx b/templates/types/streaming/nextjs/app/components/ui/chat/chat-sources.tsx
index 893541b09bb5cd0cf1f07d9a5bd0d4341a293f52..eb51b9aa80178ed80d427af3ce036195e11b227a 100644
--- a/templates/types/streaming/nextjs/app/components/ui/chat/chat-sources.tsx
+++ b/templates/types/streaming/nextjs/app/components/ui/chat/chat-sources.tsx
@@ -2,12 +2,10 @@ import { Check, Copy } from "lucide-react";
 import { useMemo } from "react";
 import { Button } from "../button";
 import { HoverCard, HoverCardContent, HoverCardTrigger } from "../hover-card";
-import { getStaticFileDataUrl } from "../lib/url";
-import { SourceData, SourceNode } from "./index";
+import { SourceData } from "./index";
 import { useCopyToClipboard } from "./use-copy-to-clipboard";
 import PdfDialog from "./widgets/PdfDialog";
 
-const DATA_SOURCE_FOLDER = "data";
 const SCORE_THRESHOLD = 0.3;
 
 function SourceNumberButton({ index }: { index: number }) {
@@ -18,46 +16,11 @@ function SourceNumberButton({ index }: { index: number }) {
   );
 }
 
-enum NODE_TYPE {
-  URL,
-  FILE,
-  UNKNOWN,
-}
-
 type NodeInfo = {
   id: string;
-  type: NODE_TYPE;
-  path?: string;
   url?: string;
 };
 
-function getNodeInfo(node: SourceNode): NodeInfo {
-  if (typeof node.metadata["URL"] === "string") {
-    const url = node.metadata["URL"];
-    return {
-      id: node.id,
-      type: NODE_TYPE.URL,
-      path: url,
-      url,
-    };
-  }
-  if (typeof node.metadata["file_path"] === "string") {
-    const fileName = node.metadata["file_name"] as string;
-    const filePath = `${DATA_SOURCE_FOLDER}/${fileName}`;
-    return {
-      id: node.id,
-      type: NODE_TYPE.FILE,
-      path: node.metadata["file_path"],
-      url: getStaticFileDataUrl(filePath),
-    };
-  }
-
-  return {
-    id: node.id,
-    type: NODE_TYPE.UNKNOWN,
-  };
-}
-
 export function ChatSources({ data }: { data: SourceData }) {
   const sources: NodeInfo[] = useMemo(() => {
     // aggregate nodes by url or file_path (get the highest one by score)
@@ -67,8 +30,11 @@ export function ChatSources({ data }: { data: SourceData }) {
       .filter((node) => (node.score ?? 1) > SCORE_THRESHOLD)
       .sort((a, b) => (b.score ?? 1) - (a.score ?? 1))
       .forEach((node) => {
-        const nodeInfo = getNodeInfo(node);
-        const key = nodeInfo.path ?? nodeInfo.id; // use id as key for UNKNOWN type
+        const nodeInfo = {
+          id: node.id,
+          url: node.url,
+        };
+        const key = nodeInfo.url ?? nodeInfo.id; // use id as key for UNKNOWN type
         if (!nodesByPath[key]) {
           nodesByPath[key] = nodeInfo;
         }
@@ -84,13 +50,12 @@ export function ChatSources({ data }: { data: SourceData }) {
       <span className="font-semibold">Sources:</span>
       <div className="inline-flex gap-1 items-center">
         {sources.map((nodeInfo: NodeInfo, index: number) => {
-          if (nodeInfo.path?.endsWith(".pdf")) {
+          if (nodeInfo.url?.endsWith(".pdf")) {
             return (
               <PdfDialog
                 key={nodeInfo.id}
                 documentId={nodeInfo.id}
                 url={nodeInfo.url!}
-                path={nodeInfo.path}
                 trigger={<SourceNumberButton index={index} />}
               />
             );
@@ -116,16 +81,16 @@ export function ChatSources({ data }: { data: SourceData }) {
 function NodeInfo({ nodeInfo }: { nodeInfo: NodeInfo }) {
   const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 1000 });
 
-  if (nodeInfo.type !== NODE_TYPE.UNKNOWN) {
+  if (nodeInfo.url) {
     // this is a node generated by the web loader or file loader,
     // add a link to view its URL and a button to copy the URL to the clipboard
     return (
       <div className="flex items-center my-2">
         <a className="hover:text-blue-900" href={nodeInfo.url} target="_blank">
-          <span>{nodeInfo.path}</span>
+          <span>{nodeInfo.url}</span>
         </a>
         <Button
-          onClick={() => copyToClipboard(nodeInfo.path!)}
+          onClick={() => copyToClipboard(nodeInfo.url!)}
           size="icon"
           variant="ghost"
           className="h-12 w-12 shrink-0"
diff --git a/templates/types/streaming/nextjs/app/components/ui/chat/index.ts b/templates/types/streaming/nextjs/app/components/ui/chat/index.ts
index 106f6294bd5138b4636da6582fc4370f027eb9d8..cb7e9272d8a6c0ea3025935d627fcf1b41bfc622 100644
--- a/templates/types/streaming/nextjs/app/components/ui/chat/index.ts
+++ b/templates/types/streaming/nextjs/app/components/ui/chat/index.ts
@@ -21,6 +21,7 @@ export type SourceNode = {
   metadata: Record<string, unknown>;
   score?: number;
   text: string;
+  url?: string;
 };
 
 export type SourceData = {
diff --git a/templates/types/streaming/nextjs/app/components/ui/chat/widgets/PdfDialog.tsx b/templates/types/streaming/nextjs/app/components/ui/chat/widgets/PdfDialog.tsx
index 00274546c2132ac9e4a3f76b1f827fc129abb664..42c2ad47d09b19c138acbe39525acad8abb6cb28 100644
--- a/templates/types/streaming/nextjs/app/components/ui/chat/widgets/PdfDialog.tsx
+++ b/templates/types/streaming/nextjs/app/components/ui/chat/widgets/PdfDialog.tsx
@@ -12,7 +12,6 @@ import {
 
 export interface PdfDialogProps {
   documentId: string;
-  path: string;
   url: string;
   trigger: React.ReactNode;
 }
@@ -26,13 +25,13 @@ export default function PdfDialog(props: PdfDialogProps) {
           <div className="space-y-2">
             <DrawerTitle>PDF Content</DrawerTitle>
             <DrawerDescription>
-              File path:{" "}
+              File URL:{" "}
               <a
                 className="hover:text-blue-900"
                 href={props.url}
                 target="_blank"
               >
-                {props.path}
+                {props.url}
               </a>
             </DrawerDescription>
           </div>
diff --git a/templates/types/streaming/nextjs/app/components/ui/lib/url.ts b/templates/types/streaming/nextjs/app/components/ui/lib/url.ts
deleted file mode 100644
index 5e2c90e598045cbbfad2dc7ae5624b53ebfe9f92..0000000000000000000000000000000000000000
--- a/templates/types/streaming/nextjs/app/components/ui/lib/url.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-const staticFileAPI = "/api/files";
-
-export const getStaticFileDataUrl = (filePath: string) => {
-  const isUsingBackend = !!process.env.NEXT_PUBLIC_CHAT_API;
-  const fileUrl = `${staticFileAPI}/${filePath}`;
-  if (isUsingBackend) {
-    const backendOrigin = new URL(process.env.NEXT_PUBLIC_CHAT_API!).origin;
-    return `${backendOrigin}${fileUrl}`;
-  }
-  return fileUrl;
-};