[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript":58,"\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript-surround":1057},[4],{"title":5,"path":6,"stem":7,"children":8,"page":57},"Blog","\u002Fblog","blog",[9,13,17,21,25,29,33,37,41,45,49,53],{"title":10,"path":11,"stem":12},"A Guide to Server-Side Rendering (SSR) with Vite and React.js","\u002Fblog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs","blog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs",{"title":14,"path":15,"stem":16},"🔄 Background DNS Refresh in Node.js: Keeping Cached IPs Updated","\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated","blog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated",{"title":18,"path":19,"stem":20},"Comprehensive Guide: Encrypting Images, Uploading to Cloudinary, and Serving Them Securely","\u002Fblog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely","blog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely",{"title":22,"path":23,"stem":24},"Comprehensive Guide to Using Uploadthing with Express and Typescript","\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript","blog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript",{"title":26,"path":27,"stem":28},"🌐 DNS Caching in Node.js: Supercharge Your App's Speed & Reliability 🚀","\u002Fblog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability","blog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability",{"title":30,"path":31,"stem":32},"Enhancing Redis for Message Queues: Using External Databases for Payload Storage","\u002Fblog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage","blog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage",{"title":34,"path":35,"stem":36},"Full Stack Learning Management System (LMS) with MERN Stack: A Complete Guide","\u002Fblog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide","blog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide",{"title":38,"path":39,"stem":40},"Getting Started with Redis: Elevating Your Web Applications","\u002Fblog\u002Fgetting-started-with-redis-elevating-your-web-applications","blog\u002Fgetting-started-with-redis-elevating-your-web-applications",{"title":42,"path":43,"stem":44},"How Queues Enhance Your Application Development Process","\u002Fblog\u002Fhow-queues-enhance-your-application-development-process","blog\u002Fhow-queues-enhance-your-application-development-process",{"title":46,"path":47,"stem":48},"Next-Gen E-Learning: Transforming Education for Students and Creators","\u002Fblog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators","blog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators",{"title":50,"path":51,"stem":52},"Single Sign-On (SSO) Implementation Using Passport.js in TypeScript","\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript","blog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript",{"title":54,"path":55,"stem":56},"Using Multer for Local File Uploads: Benefits, Trade-offs, and Cloud Transfer Integration","\u002Fblog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration","blog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration",false,{"id":59,"title":22,"author":60,"body":66,"date":1050,"description":1051,"extension":1052,"image":1053,"meta":1054,"minRead":216,"navigation":191,"path":23,"seo":1055,"stem":24,"__hash__":1056},"blog\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript.md",{"name":61,"to":62,"username":63,"avatar":64},"Sachin Thapa","https:\u002F\u002Fsachinthapa.hashnode.dev\u002F","sachinthapa572",{"src":65,"alt":61},"https:\u002F\u002Fcdn.hashnode.com\u002Fres\u002Fhashnode\u002Fimage\u002Fupload\u002Fv1733546636355\u002Fa4ae8ce5-eb4c-4ed8-ab9d-15a4b8f32ea5.png",{"type":67,"value":68,"toc":1047},"minimark",[69,73,78,81,85,88,762,766,769,796,800,809,817,820,828,832,835,937,982,986,989,993,996,999,1004,1043],[70,71,72],"p",{},"This note provides a detailed exploration of setting up file uploads using Uploadthing in an Express.js application with Typescript, focusing on security best practices and the potential use of signed URLs. The information is derived from analyzing Uploadthing's documentation, ensuring a thorough understanding for developers seeking to implement this service.",[74,75,77],"h4",{"id":76},"overview-of-uploadthing","Overview of Uploadthing",[70,79,80],{},"Uploadthing is a file upload solution designed for modern web developers, particularly those using full-stack TypeScript applications. It supports various frameworks like Next.js, Astro, Solid Start, SvelteKit, and Nuxt, with backend adapters including Express, Fastify, H3, and WinterCG\u002FFetch API, and frontend libraries such as React, Vue, SolidJS, Svelte, and Vanilla JS. This versatility makes it suitable for diverse project needs, especially in Express environments with Typescript.",[74,82,84],{"id":83},"step-by-step-setup-process","Step-by-Step Setup Process",[70,86,87],{},"To integrate Uploadthing with Express and Typescript, follow these detailed steps:",[89,90,91,109,123,515,744],"ol",{},[92,93,94,98],"li",{},[95,96,97],"strong",{},"Package Installation:",[99,100,101],"ul",{},[92,102,103,104,108],{},"Begin by installing the Uploadthing package using the command ",[105,106,107],"code",{},"npm install uploadthing",". This installs the necessary dependencies for both server and client-side operations.",[92,110,111,114],{},[95,112,113],{},"Environment Configuration:",[99,115,116],{},[92,117,118,119,122],{},"Access the Uploadthing dashboard to create a new application and retrieve an API key from the API Keys tab. Set this key as an environment variable in your project, typically as ",[105,120,121],{},"UPLOADTHING_TOKEN=your_token",". This ensures secure interaction with the Uploadthing SDK.",[92,124,125,128],{},[95,126,127],{},"File Router Creation:",[99,129,130,506],{},[92,131,132,133,136,137,140,141],{},"Create a file, such as ",[105,134,135],{},"src\u002Fuploadthing.ts",", to define your file routes using the ",[105,138,139],{},"createUploadthing"," function from \"uploadthing\u002Fexpress\". For example, to set up an image uploader:\n",[142,143,148],"pre",{"className":144,"code":145,"language":146,"meta":147,"style":147},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createUploadthing } from \"uploadthing\u002Fexpress\";\n\nconst f = createUploadthing();\n\nconst imageUploader = f({ \"image\": { maxFileSize: \"4MB\", maxFileCount: 1, acl: \"private\" } })\n  .middleware(async ({ req }) => {\n    \u002F\u002F Security check: Ensure user is authenticated\n    if (!req.user) {\n      throw new Error(\"Unauthorized\");\n    }\n  })\n  .onUploadComplete(({ file }) => {\n    \u002F\u002F Post-upload actions: Log or store the file URL\n    console.log(file.url);\n  });\n\nexport const uploadRouter = f({\n  imageUploader,\n});\n","ts","",[105,149,150,186,193,214,219,296,326,333,360,386,392,400,422,428,453,462,467,487,496],{"__ignoreMap":147},[151,152,155,159,163,167,170,173,176,180,183],"span",{"class":153,"line":154},"line",1,[151,156,158],{"class":157},"s7zQu","import",[151,160,162],{"class":161},"sMK4o"," {",[151,164,166],{"class":165},"sTEyZ"," createUploadthing",[151,168,169],{"class":161}," }",[151,171,172],{"class":157}," from",[151,174,175],{"class":161}," \"",[151,177,179],{"class":178},"sfazB","uploadthing\u002Fexpress",[151,181,182],{"class":161},"\"",[151,184,185],{"class":161},";\n",[151,187,189],{"class":153,"line":188},2,[151,190,192],{"emptyLinePlaceholder":191},true,"\n",[151,194,196,200,203,206,209,212],{"class":153,"line":195},3,[151,197,199],{"class":198},"spNyl","const",[151,201,202],{"class":165}," f ",[151,204,205],{"class":161},"=",[151,207,166],{"class":208},"s2Zo4",[151,210,211],{"class":165},"()",[151,213,185],{"class":161},[151,215,217],{"class":153,"line":216},4,[151,218,192],{"emptyLinePlaceholder":191},[151,220,222,224,227,229,232,235,238,240,244,246,249,251,254,256,258,261,263,266,269,271,275,277,280,282,284,287,289,291,293],{"class":153,"line":221},5,[151,223,199],{"class":198},[151,225,226],{"class":165}," imageUploader ",[151,228,205],{"class":161},[151,230,231],{"class":208}," f",[151,233,234],{"class":165},"(",[151,236,237],{"class":161},"{",[151,239,175],{"class":161},[151,241,243],{"class":242},"swJcz","image",[151,245,182],{"class":161},[151,247,248],{"class":161},":",[151,250,162],{"class":161},[151,252,253],{"class":242}," maxFileSize",[151,255,248],{"class":161},[151,257,175],{"class":161},[151,259,260],{"class":178},"4MB",[151,262,182],{"class":161},[151,264,265],{"class":161},",",[151,267,268],{"class":242}," maxFileCount",[151,270,248],{"class":161},[151,272,274],{"class":273},"sbssI"," 1",[151,276,265],{"class":161},[151,278,279],{"class":242}," acl",[151,281,248],{"class":161},[151,283,175],{"class":161},[151,285,286],{"class":178},"private",[151,288,182],{"class":161},[151,290,169],{"class":161},[151,292,169],{"class":161},[151,294,295],{"class":165},")\n",[151,297,299,302,305,307,310,313,317,320,323],{"class":153,"line":298},6,[151,300,301],{"class":161},"  .",[151,303,304],{"class":208},"middleware",[151,306,234],{"class":165},[151,308,309],{"class":198},"async",[151,311,312],{"class":161}," ({",[151,314,316],{"class":315},"sHdIc"," req",[151,318,319],{"class":161}," })",[151,321,322],{"class":198}," =>",[151,324,325],{"class":161}," {\n",[151,327,329],{"class":153,"line":328},7,[151,330,332],{"class":331},"sHwdD","    \u002F\u002F Security check: Ensure user is authenticated\n",[151,334,336,339,342,345,348,351,354,357],{"class":153,"line":335},8,[151,337,338],{"class":157},"    if",[151,340,341],{"class":242}," (",[151,343,344],{"class":161},"!",[151,346,347],{"class":165},"req",[151,349,350],{"class":161},".",[151,352,353],{"class":165},"user",[151,355,356],{"class":242},") ",[151,358,359],{"class":161},"{\n",[151,361,363,366,369,372,374,376,379,381,384],{"class":153,"line":362},9,[151,364,365],{"class":157},"      throw",[151,367,368],{"class":161}," new",[151,370,371],{"class":208}," Error",[151,373,234],{"class":242},[151,375,182],{"class":161},[151,377,378],{"class":178},"Unauthorized",[151,380,182],{"class":161},[151,382,383],{"class":242},")",[151,385,185],{"class":161},[151,387,389],{"class":153,"line":388},10,[151,390,391],{"class":161},"    }\n",[151,393,395,398],{"class":153,"line":394},11,[151,396,397],{"class":161},"  }",[151,399,295],{"class":165},[151,401,403,405,408,410,413,416,418,420],{"class":153,"line":402},12,[151,404,301],{"class":161},[151,406,407],{"class":208},"onUploadComplete",[151,409,234],{"class":165},[151,411,412],{"class":161},"({",[151,414,415],{"class":315}," file",[151,417,319],{"class":161},[151,419,322],{"class":198},[151,421,325],{"class":161},[151,423,425],{"class":153,"line":424},13,[151,426,427],{"class":331},"    \u002F\u002F Post-upload actions: Log or store the file URL\n",[151,429,431,434,436,439,441,444,446,449,451],{"class":153,"line":430},14,[151,432,433],{"class":165},"    console",[151,435,350],{"class":161},[151,437,438],{"class":208},"log",[151,440,234],{"class":242},[151,442,443],{"class":165},"file",[151,445,350],{"class":161},[151,447,448],{"class":165},"url",[151,450,383],{"class":242},[151,452,185],{"class":161},[151,454,456,458,460],{"class":153,"line":455},15,[151,457,397],{"class":161},[151,459,383],{"class":165},[151,461,185],{"class":161},[151,463,465],{"class":153,"line":464},16,[151,466,192],{"emptyLinePlaceholder":191},[151,468,470,473,476,479,481,483,485],{"class":153,"line":469},17,[151,471,472],{"class":157},"export",[151,474,475],{"class":198}," const",[151,477,478],{"class":165}," uploadRouter ",[151,480,205],{"class":161},[151,482,231],{"class":208},[151,484,234],{"class":165},[151,486,359],{"class":161},[151,488,490,493],{"class":153,"line":489},18,[151,491,492],{"class":165},"  imageUploader",[151,494,495],{"class":161},",\n",[151,497,499,502,504],{"class":153,"line":498},19,[151,500,501],{"class":161},"}",[151,503,383],{"class":165},[151,505,185],{"class":161},[92,507,508,509,511,512,514],{},"The ",[105,510,304],{}," function allows for authorization checks, such as verifying user login status, while ",[105,513,407],{}," handles post-upload tasks, providing access to file properties like the URL.",[92,516,517,520],{},[95,518,519],{},"Server Integration:",[99,521,522,741],{},[92,523,524,525,528,529,532,533,536,537],{},"In your main server file, typically ",[105,526,527],{},"src\u002Findex.ts",", integrate the file router with Express using the ",[105,530,531],{},"createRouteHandler"," from \"uploadthing\u002Fexpress\". Mount it at a specific endpoint, such as ",[105,534,535],{},"\u002Fapi\u002Fuploadthing",":\n",[142,538,540],{"className":144,"code":539,"language":146,"meta":147,"style":147},"import express from \"express\";\nimport { createRouteHandler } from \"uploadthing\u002Fexpress\";\nimport { uploadRouter } from \".\u002Fuploadthing\";\n\nconst app = express();\n\n\u002F\u002F Mount the Uploadthing route\napp.use(\"\u002Fapi\u002Fuploadthing\", createRouteHandler({\n  router: uploadRouter,\n}));\n\n\u002F\u002F Start the server\napp.listen(3000, () => {\n  console.log(\"Server started on port 3000\");\n});\n",[105,541,542,561,582,604,608,624,628,633,659,670,679,683,688,711,733],{"__ignoreMap":147},[151,543,544,546,549,552,554,557,559],{"class":153,"line":154},[151,545,158],{"class":157},[151,547,548],{"class":165}," express ",[151,550,551],{"class":157},"from",[151,553,175],{"class":161},[151,555,556],{"class":178},"express",[151,558,182],{"class":161},[151,560,185],{"class":161},[151,562,563,565,567,570,572,574,576,578,580],{"class":153,"line":188},[151,564,158],{"class":157},[151,566,162],{"class":161},[151,568,569],{"class":165}," createRouteHandler",[151,571,169],{"class":161},[151,573,172],{"class":157},[151,575,175],{"class":161},[151,577,179],{"class":178},[151,579,182],{"class":161},[151,581,185],{"class":161},[151,583,584,586,588,591,593,595,597,600,602],{"class":153,"line":195},[151,585,158],{"class":157},[151,587,162],{"class":161},[151,589,590],{"class":165}," uploadRouter",[151,592,169],{"class":161},[151,594,172],{"class":157},[151,596,175],{"class":161},[151,598,599],{"class":178},".\u002Fuploadthing",[151,601,182],{"class":161},[151,603,185],{"class":161},[151,605,606],{"class":153,"line":216},[151,607,192],{"emptyLinePlaceholder":191},[151,609,610,612,615,617,620,622],{"class":153,"line":221},[151,611,199],{"class":198},[151,613,614],{"class":165}," app ",[151,616,205],{"class":161},[151,618,619],{"class":208}," express",[151,621,211],{"class":165},[151,623,185],{"class":161},[151,625,626],{"class":153,"line":298},[151,627,192],{"emptyLinePlaceholder":191},[151,629,630],{"class":153,"line":328},[151,631,632],{"class":331},"\u002F\u002F Mount the Uploadthing route\n",[151,634,635,638,640,643,645,647,649,651,653,655,657],{"class":153,"line":335},[151,636,637],{"class":165},"app",[151,639,350],{"class":161},[151,641,642],{"class":208},"use",[151,644,234],{"class":165},[151,646,182],{"class":161},[151,648,535],{"class":178},[151,650,182],{"class":161},[151,652,265],{"class":161},[151,654,569],{"class":208},[151,656,234],{"class":165},[151,658,359],{"class":161},[151,660,661,664,666,668],{"class":153,"line":362},[151,662,663],{"class":242},"  router",[151,665,248],{"class":161},[151,667,590],{"class":165},[151,669,495],{"class":161},[151,671,672,674,677],{"class":153,"line":388},[151,673,501],{"class":161},[151,675,676],{"class":165},"))",[151,678,185],{"class":161},[151,680,681],{"class":153,"line":394},[151,682,192],{"emptyLinePlaceholder":191},[151,684,685],{"class":153,"line":402},[151,686,687],{"class":331},"\u002F\u002F Start the server\n",[151,689,690,692,694,697,699,702,704,707,709],{"class":153,"line":424},[151,691,637],{"class":165},[151,693,350],{"class":161},[151,695,696],{"class":208},"listen",[151,698,234],{"class":165},[151,700,701],{"class":273},"3000",[151,703,265],{"class":161},[151,705,706],{"class":161}," ()",[151,708,322],{"class":198},[151,710,325],{"class":161},[151,712,713,716,718,720,722,724,727,729,731],{"class":153,"line":430},[151,714,715],{"class":165},"  console",[151,717,350],{"class":161},[151,719,438],{"class":208},[151,721,234],{"class":242},[151,723,182],{"class":161},[151,725,726],{"class":178},"Server started on port 3000",[151,728,182],{"class":161},[151,730,383],{"class":242},[151,732,185],{"class":161},[151,734,735,737,739],{"class":153,"line":455},[151,736,501],{"class":161},[151,738,383],{"class":165},[151,740,185],{"class":161},[92,742,743],{},"This setup ensures that file upload requests are handled through the defined endpoint.",[92,745,746,749],{},[95,747,748],{},"Client-Side Implementation:",[99,750,751],{},[92,752,753,754,757,758,761],{},"On the client side, utilize the ",[105,755,756],{},"@uploadthing\u002Freact"," package to generate upload components, such as an upload button. Configure it with the server's endpoint, for example, ",[105,759,760],{},"https:\u002F\u002Fyour-server.com\u002Fapi\u002Fuploadthing",". This allows users to initiate uploads seamlessly within your application.",[74,763,765],{"id":764},"security-best-practices","Security Best Practices",[70,767,768],{},"Security is paramount when handling file uploads. Uploadthing provides several mechanisms to ensure secure operations:",[99,770,771,786],{},[92,772,773,776,777],{},[95,774,775],{},"Middleware for Authentication:"," Implement middleware within the file router to authorize users before uploads. For instance, check if a user is logged in using a service like Clerk, throwing an error if unauthorized:\n",[99,778,779],{},[92,780,781,782,785],{},"Example: ",[105,783,784],{},"throw new Error(\"You must be logged in to upload a profile picture\")"," if no user is signed in.",[92,787,788,791,792,795],{},[95,789,790],{},"Access Control Lists (ACL):"," Since version 6.0, Uploadthing allows setting the ",[105,793,794],{},"acl"," property in route configurations to \"public-read\" or \"private\". Setting it to \"private\" restricts access, ensuring only authorized users can view or download files. This is crucial for protecting sensitive data.",[74,797,799],{"id":798},"handling-file-access-and-signed-urls","Handling File Access and Signed URLs",[70,801,802,803,805,806,808],{},"Accessing uploaded files is facilitated through the ",[105,804,407],{}," callback, which provides a ",[105,807,443],{}," object containing properties like the URL. For example:",[99,810,811],{},[92,812,508,813,816],{},[105,814,815],{},"file.url"," can be used to access the uploaded file, which is particularly useful for storing in a database or sharing within the application.",[70,818,819],{},"However, for files with \"private\" ACL, direct access via URL may require additional authorization. While Uploadthing's documentation does not explicitly detail signed URLs, the concept aligns with cloud storage practices like Amazon S3, where signed URLs provide temporary access to private files. Given Uploadthing's mention of being a \"better S3\" alternative, it seems likely that similar mechanisms exist, but specific implementation details are not provided. Developers may need to:",[99,821,822,825],{},[92,823,824],{},"Refer to the storage provider's documentation (if Uploadthing uses an underlying service like S3) or",[92,826,827],{},"Contact Uploadthing support for guidance on generating signed URLs for sharing private files.",[74,829,831],{"id":830},"tables-for-clarity","Tables for Clarity",[70,833,834],{},"To organize the information, consider the following tables summarizing key aspects:",[836,837,838,860],"table",{},[839,840,841],"thead",{},[842,843,844,850,855],"tr",{},[845,846,847],"th",{},[95,848,849],{},"Step",[845,851,852],{},[95,853,854],{},"Action",[845,856,857],{},[95,858,859],{},"Details",[861,862,863,877,890,906,923],"tbody",{},[842,864,865,869,874],{},[866,867,868],"td",{},"1. Install Package",[866,870,871,872],{},"Run ",[105,873,107],{},[866,875,876],{},"Installs server and client dependencies",[842,878,879,882,887],{},[866,880,881],{},"2. Environment Setup",[866,883,884,885],{},"Set ",[105,886,121],{},[866,888,889],{},"Secure SDK interaction with API key",[842,891,892,895,903],{},[866,893,894],{},"3. File Router Creation",[866,896,897,898,900,901],{},"Define routes in ",[105,899,135],{}," using ",[105,902,139],{},[866,904,905],{},"Example: Image uploader with 4MB limit, private ACL",[842,907,908,911,917],{},[866,909,910],{},"4. Server Integration",[866,912,913,914,916],{},"Mount at ",[105,915,535],{}," in Express server",[866,918,919,920,922],{},"Use ",[105,921,531],{}," for routing",[842,924,925,928,933],{},[866,926,927],{},"5. Client Usage",[866,929,919,930,932],{},[105,931,756],{}," for upload button, set endpoint URL",[866,934,781,935],{},[105,936,760],{},[836,938,939,958],{},[839,940,941],{},[842,942,943,948,953],{},[845,944,945],{},[95,946,947],{},"Security Aspect",[845,949,950],{},[95,951,952],{},"Description",[845,954,955],{},[95,956,957],{},"Implementation",[861,959,960,971],{},[842,961,962,965,968],{},[866,963,964],{},"Middleware Authentication",[866,966,967],{},"Ensure only authorized users can upload files",[866,969,970],{},"Check user login status, throw error if unauthorized",[842,972,973,976,979],{},[866,974,975],{},"Access Control (ACL)",[866,977,978],{},"Set file access to \"public-read\" or \"private\"",[866,980,981],{},"Configure in route, affects file visibility",[74,983,985],{"id":984},"unexpected-findings","Unexpected Findings",[70,987,988],{},"An interesting observation is Uploadthing's positioning as an alternative to S3, suggesting it uses similar cloud storage technologies. This implies potential familiarity with concepts like signed URLs, but the lack of explicit documentation on this topic adds complexity, requiring developers to seek additional resources or support.",[74,990,992],{"id":991},"conclusion","Conclusion",[70,994,995],{},"This guide provides a comprehensive approach to setting up Uploadthing with Express and Typescript, emphasizing security through authentication and access controls. While accessing uploaded files is straightforward via the provided URL, handling private files with signed URLs may require further exploration, potentially through Uploadthing's support channels or underlying storage provider documentation.",[997,998],"hr",{},[1000,1001,1003],"h3",{"id":1002},"key-citations","Key Citations",[99,1005,1006,1015,1022,1029,1036],{},[92,1007,1008],{},[1009,1010,1014],"a",{"href":1011,"rel":1012},"https:\u002F\u002Fdocs.uploadthing.com\u002F",[1013],"nofollow","Uploadthing Getting Started Guide",[92,1016,1017],{},[1009,1018,1021],{"href":1019,"rel":1020},"https:\u002F\u002Fdocs.uploadthing.com\u002Fbackend-adapters\u002Fexpress",[1013],"Uploadthing Express Adapter Documentation",[92,1023,1024],{},[1009,1025,1028],{"href":1026,"rel":1027},"https:\u002F\u002Fdocs.uploadthing.com\u002Ffile-routes",[1013],"Uploadthing File Routes Documentation",[92,1030,1031],{},[1009,1032,1035],{"href":1033,"rel":1034},"https:\u002F\u002Fdocs.uploadthing.com\u002Fapi-reference\u002Fserver#create-routehandler",[1013],"Uploadthing Server API Reference",[92,1037,1038],{},[1009,1039,1042],{"href":1040,"rel":1041},"https:\u002F\u002Fdocs.uploadthing.com\u002Fapi-reference\u002Fserver#ut-api",[1013],"Uploadthing UTApi Reference",[1044,1045,1046],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":147,"searchDepth":188,"depth":188,"links":1048},[1049],{"id":1002,"depth":195,"text":1003},"2026-07-18","This note provides a detailed exploration of setting up file uploads using Uploadthing in an Express.js application with TypeScript, focusing on security best practices and the potential use of signed URLs.","md","\u002Fimages\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript.png",{},{"title":22,"description":1051},"HEzjWFhxyCCWG8xQQ9kaMNpQQfoRZAJZCufyrr9Oudo",[1058,1060],{"title":18,"path":19,"stem":20,"description":1059,"children":-1},"Learn to encrypt images, upload securely to Cloudinary, and serve them safely with this comprehensive guide on secure image handling processes",{"title":26,"path":27,"stem":28,"description":1061,"children":-1},"Optimize API performance in Node.js with DNS caching. Learn how caching reduces latency, prevents disruptions, and enhances reliability"]