# Admin Development Tips

In this chapter, you'll find some tips for developing your admin.

## Send Requests to API Routes

To send a request to an API route in the Medusa Application, use Medusa's [JS SDK](https://docs.medusajs.com/resources/js-sdk) with [Tanstack Query](https://tanstack.com/query/latest). Both of these tools are installed in your project by default.

Do not install Tanstack Query as that will cause unexpected errors in your development. If you prefer installing it for better auto-completion in your code editor, make sure to install `v5.64.2` as a development dependency.

First, create the file `src/admin/lib/sdk.ts` to set up the SDK for use in your customizations:

### Medusa Project

```ts title="src/admin/lib/sdk.ts"
import Medusa from "@medusajs/js-sdk"

export const sdk = new Medusa({
  baseUrl: import.meta.env.VITE_BACKEND_URL || "/",
  debug: import.meta.env.DEV,
  auth: {
    type: "session",
  },
})
```

### Medusa Plugin

```ts title="src/admin/lib/sdk.ts"
import Medusa from "@medusajs/js-sdk"

export const sdk = new Medusa({
  // add __BACKEND_URL__ to src/admin/vite-env.d.ts if you get type errors
  baseUrl: __BACKEND_URL__ || "/",
  auth: {
    type: "session",
  },
})
```

Notice that in a Medusa project, you use `import.meta.env` to access environment variables in your customizations, whereas in a plugin you use the global variable `__BACKEND_URL__` to access the backend URL. You can learn more in the [Admin Environment Variables](https://docs.medusajs.com/learn/fundamentals/admin/environment-variables) chapter.

Refer to the [JS SDK](https://docs.medusajs.com/resources/js-sdk#js-sdk-configurations) reference for more details on the SDK's configurations.

Then, use the configured SDK with the `useQuery` Tanstack Query hook to send `GET` requests, and the `useMutation` hook to send `POST` or `DELETE` requests.

For example:

### Query

```tsx title="src/admin/widgets/product-widget.tsx" highlights={queryHighlights}
import { defineWidgetConfig } from "@medusajs/admin-sdk"
import { Container } from "@medusajs/ui"
import { useQuery } from "@tanstack/react-query"
import { sdk } from "../lib/sdk"

const ProductWidget = () => {
  const { data, isLoading } = useQuery({
    queryFn: () => sdk.admin.product.list(),
    queryKey: ["products"],
  })
  
  return (
    <Container className="divide-y p-0">
      {isLoading && <span>Loading...</span>}
      {data?.products && (
        <ul>
          {data.products.map((product) => (
            <li key={product.id}>{product.title}</li>
          ))}
        </ul>
      )}
    </Container>
  )
}

export const config = defineWidgetConfig({
  zone: "product.list.before",
})

export default ProductWidget
```

### Mutation

```tsx title="src/admin/widgets/product-widget.tsx" highlights={mutationHighlights}
import { defineWidgetConfig } from "@medusajs/admin-sdk"
import { Button, Container } from "@medusajs/ui"
import { useMutation } from "@tanstack/react-query"
import { sdk } from "../lib/sdk"
import { DetailWidgetProps, HttpTypes } from "@medusajs/framework/types"

const ProductWidget = ({ 
  data: productData,
}: DetailWidgetProps<HttpTypes.AdminProduct>) => {
  const { mutateAsync } = useMutation({
    mutationFn: (payload: HttpTypes.AdminUpdateProduct) => 
      sdk.admin.product.update(productData.id, payload),
    onSuccess: () => alert("Product updated"),
  })

  const handleUpdate = () => {
    mutateAsync({
      title: "New Product Title",
    })
  }
  
  return (
    <Container className="divide-y p-0">
      <Button onClick={handleUpdate}>Update Title</Button>
    </Container>
  )
}

export const config = defineWidgetConfig({
  zone: "product.details.before",
})

export default ProductWidget
```

You can also send requests to custom routes, as explained in the [JS SDK reference](https://docs.medusajs.com/resources/js-sdk).

### Use Route Loaders for Initial Data

You may need to retrieve data before your component is rendered, or you may need to pass some initial data to your component to be used while data is being fetched. In those cases, you can use a [route loader](https://docs.medusajs.com/learn/fundamentals/admin/routing).

### Troubleshooting

#### No QueryClient set

If you're using `pnpm` as a package manager in your Medusa application, you might face the following error when you try to access the admin dashboard:

```bash
No QueryClient set, use QueryClientProvider to set one
```

This is a known issue when using `pnpm`. To fix it, you need to install the `@tanstack/react-query` package manually. Make sure to install the same version installed in [@medusajs/dashboard](https://github.com/medusajs/medusa/blob/d58462c9c91a3e335d03f758438e109caad1f839/packages/admin/dashboard/package.json#L54).

Learn more in the [Errors with pnpm](https://docs.medusajs.com/resources/troubleshooting/pnpm) troubleshooting guide.

***

## Global Variables in Admin Customizations

In your admin customizations, you can use the following global variables:

- `__BASE__`: The base path of the Medusa Admin, as set in the [admin.path](https://docs.medusajs.com/learn/configurations/medusa-config#path) configuration in `medusa-config.ts`.
- `__BACKEND_URL__`: The URL to the Medusa backend, as set in the [admin.backendUrl](https://docs.medusajs.com/learn/configurations/medusa-config#backendurl) configuration in `medusa-config.ts`.
- `__STOREFRONT_URL__`: The URL to the storefront, as set in the [admin.storefrontUrl](https://docs.medusajs.com/learn/configurations/medusa-config#storefrontUrl) configuration in `medusa-config.ts`.

If you get type errors while using these variables, create the file `src/admin/vite-env.d.ts` with the following content:

```ts title="src/admin/vite-env.d.ts"
/// <reference types="vite/client" />

declare const __BASE__: string
declare const __BACKEND_URL__: string
declare const __STOREFRONT_URL__: string
```

***

## Admin Translations

The Medusa Admin dashboard can be displayed in languages other than English, which is the default. Other languages are added through community contributions.

Learn how to add a new language translation for the Medusa Admin in [this guide](https://docs.medusajs.com/learn/resources/contribution-guidelines/admin-translations).


---

The best way to deploy Medusa is through Medusa Cloud where you get autoscaling production infrastructure fine tuned for Medusa. Create an account by signing up at cloud.medusajs.com/signup.
