{"id":37205,"date":"2025-03-10T07:00:00","date_gmt":"2025-03-10T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=37205"},"modified":"2025-11-06T15:12:30","modified_gmt":"2025-11-06T23:12:30","slug":"how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","title":{"rendered":"How to Build a Project for TanStack Start Image Optimization and Uploading"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>If you\u2019ve been working in the React ecosystem for a while, you\u2019re probably familiar with some of the <a href=\"https:\/\/tanstack.com\">TanStack libraries<\/a> like Router or <a href=\"https:\/\/tanstack.com\/query\/latest\">Query<\/a>. <a href=\"https:\/\/tanstack.com\/start\/latest\">TanStack Start<\/a> is a new full-stack React framework powered by <a href=\"https:\/\/tanstack.com\/router\/latest\">TanStack Router<\/a>. It doesn\u2019t yet have all the bells and whistles that a more established framework like <a href=\"https:\/\/nextjs.org\/\">Next.js<\/a> has, so there isn\u2019t a component that automatically handles optimizing images on your site or a third-party Cloudinary framework integration. Still, we can add image\/video optimization and much more to our TanStack Start website with the <a href=\"https:\/\/cloudinary.com\/documentation\/react_integration\">Cloudinary React SDK<\/a>.<\/p>\n<h2>Tanstack Router vs. React Router<\/h2>\n<p>Just to give a little context, a TanStack Router and React Router are both routing libraries for React applications, but they differ in design philosophy and flexibility. React Router is the long-established standard, providing a straightforward way to manage navigation and dynamic routes within React apps. TanStack Router, a newer alternative from the creators of React Query, is designed for type safety, data loading, and better integration with modern React features like hooks and suspense. It focuses on predictable, data-driven routing with built-in support for loaders, optimistic updates, and URL state management. In essence, React Router is simpler and widely used, while TanStack Router is more advanced and tailored for complex, data-heavy applications.<\/p>\n<p>So far we\u2019ve given context for what is Tanstack Start and a comparison of Tanstack router vs React router. Now, we\u2019ll create a simple TanStack Start project and add image optimization and uploading features using the Cloudinary React SDK.<\/p>\n<p>If you don\u2019t have Cloudinary, you can <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">sign up now for free and for life<\/a>. You\u2019ll get access to be able to follow along here as well as all of Cloudinary.<\/p>\n<h2>Getting Started With TanStack Start<\/h2>\n<p>There isn\u2019t a fancy tool for starting a new TanStack Start project like you might get with Next or Astro quite yet. The easiest way to get started is to copy one of the example projects available in the project repository. For this demo, I\u2019ll copy over the <code>start-basic<\/code> example project.<\/p>\n<p>Once you have the <code>start-basic<\/code> directory copied over to your computer, navigate to the directory in your terminal. We can install the dependencies and start the dev server to see what the basic project looks like.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm i\n<\/code><\/span><\/pre>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm run dev\n<\/code><\/span><\/pre>\n<p>The dev server will start at <a href=\"http:\/\/localhost:3000\">http:\/\/localhost:3000<\/a>. We get a basic web page with a navigation bar that we can use to navigate to some of the example pages.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1741647705\/blog-How_to_Build_a_TanStack_Start_Project_for_Image_Optimization_and_Uploading-1.png\" alt=\"Image showing a screenshot of Tanstack Start image optimization dev environment\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1296\" height=\"928\"\/><\/p>\n<h3>Project Structure<\/h3>\n<p>Now that we know what the site looks like, we\u2019ll dive into how the project is structured. All the code lives in the <code>app<\/code> directory.<\/p>\n<p>Here are the important parts that we\u2019ll do most of our work in:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">- components <span class=\"hljs-comment\"># directory for our React components<\/span>\n- routes <span class=\"hljs-comment\"># TanStack Start\/Router file-based routing<\/span>\n- styles <span class=\"hljs-comment\"># css styles<\/span>\n- utils <span class=\"hljs-comment\"># js utilities<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If you open up the routes directory, the naming convention may look a little strange at first. You can find all the details on the <a href=\"https:\/\/tanstack.com\/router\/latest\/docs\/framework\/react\/guide\/file-based-routing\">file-based routing conventions here<\/a>.<\/p>\n<h2>Integrating Cloudinary<\/h2>\n<p>Now that we\u2019re familiar with our new TanStack Start website, let\u2019s plan out our new features.<\/p>\n<p>First, we want to be able to upload images of our users to our Media Library.<\/p>\n<p>Next, we\u2019ll create an Avatar component to serve optimized avatar images of our users.<\/p>\n<p>Because we haven\u2019t set up a real database yet, our avatar images won\u2019t be linked to any specific users on the demo site. In this post, they\u2019re purely for illustration, but you can easily configure them to use real data.<\/p>\n<h3>Initial Setup<\/h3>\n<p>To get started, we\u2019ll need to install our Cloudinary dependencies:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-keyword\">@cloudinary<\/span>\/url-gen @cloudinary\/react\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h4>Add Types for the Cloudinary Upload Widget<\/h4>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-selector-tag\">-D<\/span> <span class=\"hljs-keyword\">@types<\/span>\/cloudinary-uploadwidget-browser\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Add the following key to your <code>compilerOptions<\/code> in <code>tsconfig.json<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-string\">\"types\"<\/span>: &#91;<span class=\"hljs-string\">\"@types\/cloudinary-uploadwidget-browser\"<\/span>],\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, let\u2019s create a file named <code>cloudinary.ts<\/code> in our <code>app<\/code> directory. This file will create and export our configured Cloudinary instance:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> cld = <span class=\"hljs-keyword\">new<\/span> Cloudinary({\n  <span class=\"hljs-attr\">cloud<\/span>: {\n    <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">'demo'<\/span>\n  }\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><em>Replace \u2018demo\u2019 with your own cloud name.<\/em><\/p>\n<p>To use the Upload widget, we\u2019ll need to add the script to our RootDocument component <code>\/app\/routes\/__root.tsx<\/code>. We can put it right below the framework\u2019s <code>&lt;Scripts \/&gt;<\/code> tag:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">        {children}\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ScrollRestoration<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TanStackRouterDevtools<\/span> <span class=\"hljs-attr\">position<\/span>=<span class=\"hljs-string\">\"bottom-right\"<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Scripts<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>\n          <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/upload-widget.cloudinary.com\/latest\/global\/all.js\"<\/span>\n          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>\n        &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n  ) \n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h3>Adding the Avatar Uploader<\/h3>\n<p>We\u2019ll use the Upload widget to handle uploading avatar images to our media library. Let\u2019s create the file for our component <code>app\/components\/CloudinaryUploadWidget.tsx<\/code>.<\/p>\n<p>We\u2019ll need to add our cloud name and an upload preset to the Upload widget config. If you\u2019re not familiar with upload presets, you can <a href=\"https:\/\/cloudinary.com\/documentation\/upload_presets\">learn how to set one up here<\/a>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useRef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\ndeclare global {\n  interface Window {\n    <span class=\"hljs-attr\">cloudinary<\/span>: CloudinaryBase;\n  }\n}\n\ninterface CloudinaryUploadWidgetProps {\n onUpload?: <span class=\"hljs-function\">(<span class=\"hljs-params\">publicId: string<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> CloudinaryUploadWidget: React.FC&lt;CloudinaryUploadWidgetProps&gt; = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ uwConfig, setPublicId }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> uploadWidgetRef = useRef&lt;any&gt;(<span class=\"hljs-literal\">null<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> uploadButtonRef = useRef&lt;HTMLButtonElement&gt;(<span class=\"hljs-literal\">null<\/span>);\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> initializeUploadWidget = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">if<\/span> (<span class=\"hljs-built_in\">window<\/span>.cloudinary &amp;&amp; uploadButtonRef.current) {\n        <span class=\"hljs-comment\">\/\/ Create upload widget<\/span>\n        uploadWidgetRef.current = <span class=\"hljs-built_in\">window<\/span>.cloudinary.createUploadWidget(\n          {\n\t          <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"your_cloud_name\"<\/span>,\n\t          <span class=\"hljs-attr\">uploadPreset<\/span>: <span class=\"hljs-string\">\"upload_preset_id\"<\/span>\n          },\n          (error: any, <span class=\"hljs-attr\">result<\/span>: any) =&gt; {\n            <span class=\"hljs-keyword\">if<\/span> (!error &amp;&amp; result &amp;&amp; result.event === <span class=\"hljs-string\">'success'<\/span>) {\n              <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Upload successful:'<\/span>, result.info);\n              onUpload?.(result.info.public_id);\n            }\n          }\n        );\n\n        <span class=\"hljs-comment\">\/\/ Add click event to open widget<\/span>\n        <span class=\"hljs-keyword\">const<\/span> handleUploadClick = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n          <span class=\"hljs-keyword\">if<\/span> (uploadWidgetRef.current) {\n            uploadWidgetRef.current.open();\n          }\n        };\n\n        <span class=\"hljs-keyword\">const<\/span> buttonElement = uploadButtonRef.current;\n        buttonElement.addEventListener(<span class=\"hljs-string\">'click'<\/span>, handleUploadClick);\n\n        <span class=\"hljs-comment\">\/\/ Cleanup<\/span>\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n          buttonElement.removeEventListener(<span class=\"hljs-string\">'click'<\/span>, handleUploadClick);\n        };\n      }\n    };\n\n    initializeUploadWidget();\n  }, &#91;onUpload]);\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n      <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{uploadButtonRef}<\/span>\n      <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"upload_widget\"<\/span>\n      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"<\/span>\n    &gt;<\/span>\n      Upload\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span>\n  );\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The component we created will display a button that opens the Upload Widget.<\/p>\n<h3>Add Upload Widget to User Page<\/h3>\n<p>Now that we have our Upload widget ready, we can add it to our user page. Let\u2019s open the page up in our routes directory <code>app\/routes\/users.$userId.tsx<\/code><\/p>\n<p>Currently, this page just shows the user name and email. Let\u2019s add our uploader button below them:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ existing code...<\/span>\n<span class=\"hljs-keyword\">import<\/span> { CloudinaryUploadWidget } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'~\/components\/CloudinaryUploadWidget'<\/span>\n\n<span class=\"hljs-comment\">\/\/ exisiting code...<\/span>\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">UserComponent<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> user = Route.useLoaderData()\n  \n  <span class=\"hljs-keyword\">const<\/span> handleUpload = <span class=\"hljs-function\">(<span class=\"hljs-params\">publicId: string<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-comment\">\/\/ In our real application we could update the user to set the avatar value in the database<\/span>\n    <span class=\"hljs-comment\">\/\/ IE: updateUser({ avatarPublicId: publicId });<\/span>\n    <span class=\"hljs-built_in\">console<\/span>.log(publicId);\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"space-y-2\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-xl font-bold underline\"<\/span>&gt;<\/span>{user.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-sm\"<\/span>&gt;<\/span>{user.email}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryUploadWidget<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can imagine using the <code>onUpload<\/code> prop to our <code>CloudinaryUploadWidget<\/code> to save the avatar id to our user record in the database. We added an example in the comments. We\u2019ll use this example field to add avatar images to our User route.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1741647705\/blog-How_to_Build_a_TanStack_Start_Project_for_Image_Optimization_and_Uploading-2.png\" alt=\"Image showing screenshot of Cloudinary image upload environment used in the Tanstack Start image optimization project\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1858\" height=\"1746\"\/><\/p>\n<h3>Creating a <code>UserAvatar<\/code> component<\/h3>\n<p>Next we\u2019ll create a <code>UserAvatar<\/code> component and use it to render optimized avatar images on our user route. We\u2019ll use the <code>AdvancedImage<\/code> component from the <code>@cloudinary\/react<\/code> SDK to render the image after we apply some transformations with <code>@cloudinary\/url-gen<\/code> to optimize the image for user avatars.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { AdvancedImage } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { thumbnail } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen\/actions\/resize'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { focusOn } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen\/qualifiers\/gravity'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { FocusOn } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen\/qualifiers\/focusOn'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { cld } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/cloudinary'<\/span>\n\ninterface UserAvatarProps {\n  publicId?: string\n  size?: number\n  className?: string\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">UserAvatar<\/span>(<span class=\"hljs-params\">{ publicId, size = <span class=\"hljs-number\">150<\/span>, className = <span class=\"hljs-string\">''<\/span> }: UserAvatarProps<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (!publicId) {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> \n        <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">bg-gray-200<\/span> <span class=\"hljs-attr\">rounded-full<\/span> <span class=\"hljs-attr\">flex<\/span> <span class=\"hljs-attr\">items-center<\/span> <span class=\"hljs-attr\">justify-center<\/span> ${<span class=\"hljs-attr\">className<\/span>}`}\n        <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">width:<\/span> <span class=\"hljs-attr\">size<\/span>, <span class=\"hljs-attr\">height:<\/span> <span class=\"hljs-attr\">size<\/span> }}\n      &gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-gray-500 text-2xl\"<\/span>&gt;<\/span>?<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    )\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> image = cld.image(publicId)\n    .resize(thumbnail().width(size).height(size).gravity(focusOn(FocusOn.face())))\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{className}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">AdvancedImage<\/span> <span class=\"hljs-attr\">cldImg<\/span>=<span class=\"hljs-string\">{image}<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n} \n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019ll create a <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformations.html\">transformation pipeline<\/a> for our user avatar images that uses AI to detect faces, crops the image to focus on the detected face, and resizes it to the specified dimensions. The <code>AdvancedImage<\/code> component serves and renders this image through Cloudinary\u2019s CDN.<\/p>\n<h3>Adding an Avatar Image to User Route<\/h3>\n<p>Now that we have our <code>UserAvatar<\/code> component, we can use it to add avatar images to our Users route.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ existing code...<\/span>\n<span class=\"hljs-keyword\">import<\/span> { UserAvatar } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'~\/components\/UserAvatar'<\/span>\n\n<span class=\"hljs-comment\">\/\/ exisiting code...<\/span>\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">UserComponent<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> user = Route.useLoaderData()\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"space-y-4\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex items-center gap-4\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UserAvatar<\/span> <span class=\"hljs-attr\">publicId<\/span>=<span class=\"hljs-string\">{user.avatarPublicId}<\/span> <span class=\"hljs-attr\">size<\/span>=<span class=\"hljs-string\">{100}<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-xl font-bold underline\"<\/span>&gt;<\/span>{user.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-sm\"<\/span>&gt;<\/span>{user.email}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryUploadWidget<\/span> <span class=\"hljs-attr\">onUpload<\/span>=<span class=\"hljs-string\">{handleUpload}<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1741647705\/blog-How_to_Build_a_TanStack_Start_Project_for_Image_Optimization_and_Uploading-3.png\" alt=\"Image showing screenshot of Tanstack Start image avatar environment\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1180\" height=\"754\"\/><\/p>\n<h2>Summary<\/h2>\n<p>Cloudinary\u2019s React SDK and Upload widget make integrating media optimizations and uploads a quick and simple process for any React framework. TanStack Start is a powerful new framework for building React applications and has quite a few stand-out features and a lot in common with the popular Remix framework.<\/p>\n<p>In this post, we added the Cloudinary Upload widget to upload user avatar images in our application. After that, we created an optimized <code>UserAvatar<\/code> component using Cloudinary\u2019s transformations and the <code>AdvancedImage<\/code> component.<\/p>\n<p>This is a great starting point, so you can easily add optimizations for other images throughout your application. Check out other <a href=\"https:\/\/cloudinary.com\/documentation\/react_sample_projects\">React sample projects<\/a> to help you get started integrating Cloudinary and <a href=\"https:\/\/cloudinary.com\/users\/register_free\">sign up for a free account today<\/a>.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":37206,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[227,246,373],"class_list":["post-37205","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-performance-optimization","tag-react","tag-upload"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>TanStack Start Image | Upload and Optimize Images Using Cloudinary React SDK<\/title>\n<meta name=\"description\" content=\"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build a Project for TanStack Start Image Optimization and Uploading\" \/>\n<meta property=\"og:description\" content=\"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-10T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-06T23:12:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"How to Build a Project for TanStack Start Image Optimization and Uploading\",\"datePublished\":\"2025-03-10T14:00:00+00:00\",\"dateModified\":\"2025-11-06T23:12:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\"},\"wordCount\":12,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA\",\"keywords\":[\"Performance Optimization\",\"React\",\"Upload\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\",\"url\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\",\"name\":\"TanStack Start Image | Upload and Optimize Images Using Cloudinary React SDK\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA\",\"datePublished\":\"2025-03-10T14:00:00+00:00\",\"dateModified\":\"2025-11-06T23:12:30+00:00\",\"description\":\"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA\",\"width\":2000,\"height\":1100,\"caption\":\"Image showing graphic representation of Tanstack Start image optimization using an image of a tennis player, a screenshot of code and the Cloudinary logo\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build a Project for TanStack Start Image Optimization and Uploading\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"TanStack Start Image | Upload and Optimize Images Using Cloudinary React SDK","description":"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","og_locale":"en_US","og_type":"article","og_title":"How to Build a Project for TanStack Start Image Optimization and Uploading","og_description":"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.","og_url":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","og_site_name":"Cloudinary Blog","article_published_time":"2025-03-10T14:00:00+00:00","article_modified_time":"2025-11-06T23:12:30+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"How to Build a Project for TanStack Start Image Optimization and Uploading","datePublished":"2025-03-10T14:00:00+00:00","dateModified":"2025-11-06T23:12:30+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading"},"wordCount":12,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","keywords":["Performance Optimization","React","Upload"],"inLanguage":"en-US","copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","url":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading","name":"TanStack Start Image | Upload and Optimize Images Using Cloudinary React SDK","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","datePublished":"2025-03-10T14:00:00+00:00","dateModified":"2025-11-06T23:12:30+00:00","description":"Learn how to create a TanStack Start project with image optimization and uploading features using the Cloudinary React SDK for free.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","width":2000,"height":1100,"caption":"Image showing graphic representation of Tanstack Start image optimization using an image of a tennis player, a screenshot of code and the Cloudinary logo"},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-a-tanstack-start-project-for-image-optimization-and-uploading#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Build a Project for TanStack Start Image Optimization and Uploading"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1741633811\/Blog_Upload_and_optimize_images_in_TanStack_Start\/Blog_Upload_and_optimize_images_in_TanStack_Start.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/37205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=37205"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/37205\/revisions"}],"predecessor-version":[{"id":39124,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/37205\/revisions\/39124"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/37206"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=37205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=37205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=37205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}