What's your biggest current challenge? Have your say in Community Polls along the right column.

Best Practices for Running One-Time Initialization Code in a Shopify App

Best Practices for Running One-Time Initialization Code in a Shopify App

Kit_
Shopify Partner
22 1 5

Hi Developers,

 

I’m working on a Shopify Custom distribution app built with Remix.js, and I’m trying to figure out the best way to run some one-time setup code when the app is installed. For example, I want to create a placeholder product for the app and save its ID as a metafield during the installation process.

 

I know that in Remix, the entry.server.tsx file runs on every request, so it’s not the right place for code that should only execute once. Right now, I’m thinking of using the OAuth callback to handle this setup:

 

- Check if the placeholder product already exists (querying the store metafields).

- If it doesn’t exist, create the placeholder product and save its ID in a metafield.

 

Then, during regular app usage, I’d just check the metafield or cache the ID in a database to avoid running this logic repeatedly.

 

Does this approach make sense? Or is there a better way to handle one-time initialization tasks in a Shopify app that supports multi-store installs?

 

I’d greatly appreciate any insights or recommendations.

 

Many thanks,

Ankit Khand

Reply 1 (1)
Kit_
Shopify Partner
22 1 5

Hi Jacbo,

 

Thank you so much for your feeback.

I know the logic but what i not quite sure is where to put the logic?

 

For example, below is my code but i am not quite sure where to put this code? Is it under routes/auth/callback.tsx?

app.post("/auth/callback", async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(req, res);

// Query metafields to check for existing placeholder product
const query = `
query getPlaceholderProduct {
shop {
metafields(first: 1, namespace: "custom_app", key: "placeholder_product_id") {
edges {
node {
value
}
}
}
}
}
`;
const response = await Shopify.Clients.Graphql.query({
session,
data: query,
});

const placeholderExists =
response?.body?.data?.shop?.metafields?.edges.length > 0;

if (!placeholderExists) {
// Create placeholder product if it doesn't exist
const mutation = `
mutation createAppPlaceholderProduct {
productCreate(input: {
title: "App Placeholder Product",
status: DRAFT,
variants: [{ price: "0.00" }]
}) {
product {
id
}
}
}
`;
const createResponse = await Shopify.Clients.Graphql.query({
session,
data: mutation,
});

const productId = createResponse.body?.data?.productCreate?.product?.id;

// Save the product ID as a metafield
const saveMutation = `
mutation savePlaceholderProductId($productId: ID!) {
metafieldsSet(input: {
metafields: [{
namespace: "custom_app",
key: "placeholder_product_id",
type: "single_line_text_field",
value: $productId
}]
}) {
userErrors {
field
message
}
}
}
`;
await Shopify.Clients.Graphql.query({
session,
data: saveMutation,
variables: { productId },
});
}

// Redirect to the app's dashboard after setup
res.redirect(`/dashboard?shop=${session.shop}`);
});


Many thanks