How to create an structured Metafield in app?

import { Card, Page, Text } from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import { PrismaClient } from "@prisma/client";
import { useLoaderData } from "@remix-run/react";

// Initialize Prisma client
const prisma = new PrismaClient();

export const loader = async ({ request }) => {
  // Authenticate the request to get the session and admin client
  const { session, admin } = await authenticate.admin(request);
  const shop = session.shop;

  // Query the Session table to get the accessToken for the shop
  const sessionRecord = await prisma.session.findFirst({
    where: { shop },
    select: { accessToken: true },
  });

  if (!sessionRecord) {
    throw new Error(`No session found for shop: ${shop}`);
  }

  const accessToken = sessionRecord.accessToken;

  // Fetch all products from Shopify Admin API
  const apiUrl = `https://${shop}/admin/api/2025-07/products.json`;

  try {
    const response = await fetch(apiUrl, {
      method: "GET",
      headers: {
        "X-Shopify-Access-Token": accessToken,
      },
    });

    if (!response.ok) {
      throw new Error(`Failed to fetch products: ${response.statusText}`);
    }

    const data = await response.json();
    const products = data.products || [];

    // Check if metafields have already been processed for this shop
    const shopMetafieldCheck = await admin.graphql(
      `
        query {
          shop {
            metafield(namespace: "app_config", key: "metafields_initialized") {
              value
            }
          }
        }
      `,
    );

    const shopMetafieldData = await shopMetafieldCheck.json();
    const metafieldsInitialized =
      shopMetafieldData.data?.shop?.metafield?.value === "true";

    if (!metafieldsInitialized) {
      // GraphQL query to check existing metafields for a product
      const metafieldQuery = `
        query($id: ID!) {
          product(id: $id) {
            id
            title
            metafield(namespace: "shipping", key: "flat_rate") {
              id
              value
            }
          }
        }
      `;

      // GraphQL mutation to update product with metafield
      const mutation = `
        mutation productUpdate($input: ProductInput!) {
          productUpdate(input: $input) {
            product {
              id
              title
              metafield(namespace: "shipping", key: "flat_rate") {
                id
                namespace
                key
                value
                type
              }
            }
            userErrors {
              field
              message
            }
          }
        }
      `;

      const errors = [];
      const successes = [];

      // Iterate over products to check and create metafields
      for (const product of products) {
        try {
          // Convert REST API product ID to GraphQL GID
          const productGid = `gid://shopify/Product/${product.id}`;

          // Check if the product already has the metafield
          const metafieldCheck = await admin.graphql(metafieldQuery, {
            variables: { id: productGid },
          });

          const metafieldData = await metafieldCheck.json();
          const existingMetafield = metafieldData.data?.product?.metafield;

          // Only create the metafield if it doesn't exist
          if (!existingMetafield) {
            const fieldResponse = await admin.graphql(mutation, {
              variables: {
                input: {
                  id: productGid,
                  metafields: [
                    {
                      namespace: "shipping",
                      key: "flat_rate",
                      value: "0.0",
                      type: "number_decimal",
                    },
                  ],
                },
              },
            });

            const responseData = await fieldResponse.json();
            const userErrors =
              responseData.data?.productUpdate?.userErrors || [];

            if (userErrors.length > 0) {
              errors.push({
                productId: product.id,
                title: product.title,
                errors: userErrors,
              });
            } else {
              successes.push({
                productId: product.id,
                title: product.title,
                metafield: responseData.data?.productUpdate?.product?.metafield,
              });
            }
          } else {
            // Optionally track products that already had the metafield
            successes.push({
              productId: product.id,
              title: product.title,
              metafield: existingMetafield,
              message: "Metafield already exists",
            });
          }
        } catch (error) {
          errors.push({
            productId: product.id,
            title: product.title,
            errors: [{ message: error.message }],
          });
        }
      }

      // Mark the shop as initialized by setting a shop-level metafield
      if (errors.length === 0 || successes.length > 0) {
        await admin.graphql(
          `
            mutation shopMetafieldsSet($metafields: [MetafieldsSetInput!]!) {
              metafieldsSet(metafields: $metafields) {
                metafields {
                  id
                  namespace
                  key
                  value
                }
                userErrors {
                  field
                  message
                }
              }
            }
          `,
          {
            variables: {
              metafields: [
                {
                  namespace: "app_config",
                  key: "metafields_initialized",
                  value: "true",
                  type: "boolean",
                  ownerId: `gid://shopify/Shop/${session.shopId}`,
                },
              ],
            },
          },
        );
      }

      return {
        accessToken,
        products,
        successes,
        errors: errors.length > 0 ? errors : null,
      };
    }

    return { accessToken, products, successes: [], errors: null };
  } catch (error) {
    console.error("Error in loader:", error);
    return {
      accessToken,
      products: [],
      successes: [],
      errors: [{ message: error.message }],
    };
  }
};

export default function Index() {
  // Retrieve data from loader
  const { successes, errors } = useLoaderData();

  return (
    <Page title="Product Shipping Flat Rate App">
      <Card>
        <Text variant="headingMd" as="h2">
          Welcome
        </Text>
        <Text as="p">
          This app has automatically set a flat shipping rate metafield for
          products that did not already have it.
        </Text>
        {errors && (
          <Text as="p" tone="critical">
            Errors occurred during metafield creation:
            {errors.map((error, index) => (
              <div key={index}>
                Product {error.title} (ID: {error.productId}):{" "}
                {error.errors.map((e) => e.message).join(", ")}
              </div>
            ))}
          </Text>
        )}
        {successes?.length > 0 && (
          <Text as="p" tone="success">
            Processed {successes.length} products. Metafields created or already
            existed.
          </Text>
        )}
      </Card>
    </Page>
  );
}

Hi, everyone i am creating an metafield using graphql its working fine but its creating unstructured metafield but i want to create an structured metafield how can i do that please help me with this. Thank you for you response in advance

Thank You.