Essentials

Admin API

Using the Shopify Admin API in Nuxt

The Admin API is a private API that allows you to manage your Shopify store's data, such as orders, customers, products, and inventory. It is designed to be used in server-side applications only, as it requires credentials that should never be exposed to the client.

See the module configuration to see how to set up the module for the Admin API. If you need help obtaining your credentials, see the Shopify Setup Guide.

Authentication

The module supports multiple authentication methods for the Admin API:

The recommended method for apps created via the Shopify Dev Dashboard. The module automatically obtains and refreshes access tokens using your client ID and secret.

nuxt.config.ts
export default defineNuxtConfig({
  shopify: {
    name: "quickstart-abcd1234",
    clients: {
      admin: {
        apiVersion: "2026-01",
        clientId: "YOUR_CLIENT_ID",
        clientSecret: "YOUR_CLIENT_SECRET",
      },
    },
  },
})

Access tokens are valid for 24 hours and are automatically refreshed before expiry.

Token Storage

When using client credentials or refresh tokens, the module stores obtained tokens using Unstorage. By default, tokens are stored in memory. You can configure a persistent storage driver:

nuxt.config.ts
export default defineNuxtConfig({
  shopify: {
    clients: {
      admin: {
        // Use a custom storage mount name
        tokenStorage: "my-token-store",

        // Or configure a driver directly
        tokenStorage: {
          driver: "redis",
          host: "localhost",
          port: 6379,
        },
      },
    },
  },

  nitro: {
    storage: {
      "my-token-store": {
        driver: "redis",
        host: "localhost",
        port: 6379,
      },
    },
  },
})

Usage

Once configured, you can use the Admin API in your Nuxt application via the useAdmin composable. This composable can only be used on the server-side (in server routes, middleware, or server-only composables).

Server-side

useAdmin

~/server/api/orders.ts
export default defineEventHandler(async (event) => {
  const admin = useAdmin()

  return admin.request(`#graphql
    query GetOrders($first: Int!) {
      orders(first: $first) {
        edges {
          node {
            id
            name
            totalPrice
            createdAt
          }
        }
      }
    }
  `, {
    variables: {
      first: 10,
    },
  })
})

You can also wrap the useAdmin composable in another composable to build an abstracted data fetching method:

~/server/utils/useOrder.ts
export const useOrder = async (id: string) => {
  const admin = useAdmin()

  return admin.request(`#graphql
    query GetOrder($id: ID!) {
      order(id: $id) {
        id
        name
        totalPrice
        lineItems(first: 10) {
          edges {
            node {
              title
              quantity
            }
          }
        }
      }
    }
  `, {
    variables: {
      id,
    },
  })
}

Using validation

Using Nitro's built-in input validation, you can match the variables of your GraphQL queries before sending them to the API.

For this example we'll use the Zod library, but you can use any validation library you like.

First, install the validation library:

npm install zod

Then, import it and create a schema:

import { z } from "zod"

const schema = z.object({
  first: z.preprocess(v => Number(v), z.number().min(1).max(250)),
  status: z.enum(["OPEN", "CLOSED", "CANCELLED"]).optional(),
})

Next, we can use Nitro's built-in getValidatedQuery utility to validate the query variables:

~/server/api/orders.ts
import { z } from "zod"

const schema = z.object({
  first: z.preprocess(v => Number(v), z.number().min(1).max(250)),
  status: z.enum(["OPEN", "CLOSED", "CANCELLED"]).optional(),
})

export default defineEventHandler(async (event) => {
  const admin = useAdmin()
  const variables = await getValidatedQuery(event, schema.parse)

  const query = `#graphql
    query FetchOrders($first: Int!, $status: OrderStatus) {
      orders(first: $first, query: $status) {
        edges {
          node {
            id
            name
            totalPrice
            financialStatus
            fulfillmentStatus
          }
        }
      }
    }
  `

  return admin.request(query, { variables })
})

Now we can call the API at /api/orders with the following variables:

~/pages/admin/orders.vue
const { data: orders } = await useFetch("/api/orders", {
  query: {
    first: 50,
    status: "OPEN",
  },
})

Now the request will fail before reaching Shopify if the variables don't match the schema.

Copyright © 2026