Shopify app development path
Learn to build Shopify apps by building a real one.
One app, built end to end on your own development store, with the fundamentals explained as you go. The first 15 lessons are free.
Start the path →While you run shopify app dev, Shopify loads your app from a generated URL that points back at your laptop. Once the app runs on a host, Shopify needs the host's address instead. Make a production config, and in it change these lines:
application_url = "https://my-app.example.com" [auth]redirect_urls = [ "https://my-app.example.com/auth/callback",] [build]automatically_update_urls_on_dev = falseThen push the config to Shopify:
shopify app deploy --config productionShopify's guide writes the same two URLs as SHOPIFY_APP_URL and <SHOPIFY_APP_URL>/auth/callback. The /auth/callback path comes from the React Router app template. If your own server handles the callback somewhere else, use that path.
What runs where
In development the CLI does two jobs for you. It runs your web app on your machine, and it keeps your app's URLs on Shopify's side pointed at it. Shopify's reference says so directly: with the --no-update flag, shopify app dev uses the app URL from your TOML file "instead an autogenerated URL for dev". Without it, you get the generated one.
In production neither job exists. Your host runs the web app, and Shopify only knows the addresses written in your app's configuration. That is why one command matters so much here: shopify app deploy builds your app configuration and extensions and releases them as a new version, but it does not deploy your web app. You put the web app on the host yourself, with whatever your provider uses.
Use a second app for production
Shopify recommends a separate app for production. It can use the same repository and the same code, but it has its own record and its own configuration in the Dev Dashboard. It also fits how the config file behaves: changes to shopify.app.toml are applied automatically during app dev for your chosen development store, and reach every store in production only when you run deploy. Keep your experiments on the dev app and your real merchants on the other one.
shopify app config link creates or links the config file for the second app. Name it something you will recognise, like shopify.app.production.toml. From then on, --config production picks it for a single command, and shopify app config use sets the default for every command after it.
Switch back when you are done
Shopify's guide has a caution for this exact moment: after you deploy the production config, run shopify app config use to go back to your development config. Otherwise your next shopify app dev runs against the production app.
The lines that change
| Setting | In development | In production |
|---|---|---|
application_url | Generated by the CLI for each dev session | Your host's URL, with https |
[auth] redirect_urls | Generated to match the dev URL | Your host's URL plus your callback path |
[build] automatically_update_urls_on_dev | true, or you are asked on first run | false, which Shopify recommends for production apps |
Any other absolute URL, for example [app_proxy] url | Your dev URL | Your host's URL |
The flag in the third row is the one people skip. Shopify describes it plainly: when it is true, your app URL and redirect URLs are updated automatically on dev. When it is false, your URLs are not touched. On a production config you want the second behaviour, so a stray app dev cannot rewrite the addresses your merchants use.
What the host needs
Your host needs the same app's credentials as environment variables. shopify app env show prints the values for the linked app. From Shopify's table:
| Variable | Required | What it is |
|---|---|---|
SHOPIFY_APP_URL | Yes | The deployed URL, with protocol. Must match application_url. |
SHOPIFY_API_KEY | Yes | The client ID of the production app. |
SHOPIFY_API_SECRET | Yes | The client secret. Store it as a secret, never commit it. |
SCOPES | No | Optional when you use Shopify-managed installation. |
PORT | No | Defaults to 3000. |
One more thing changes outside the TOML file. The template starts on SQLite through Prisma, which Shopify's guide says to replace with something like Postgres or MySQL for production. Shopify notes that SQLite has limits with multiple containers and at scale, and that providers such as Fly.io may reset disk storage, which wipes a SQLite database. Session data includes access tokens, so Shopify also tells you to encrypt it at rest.
What each skipped step costs you
Every item here follows from what the setting is documented to do:
- application_url left on the dev value. Shopify embeds your app by loading the URL on file in an iframe. A generated dev URL belongs to a dev session, so it stops answering when
app devdoes. - redirect_urls missing your host. These are the addresses Shopify sends merchants back to during the authorization code grant, and Shopify requires at least one before an app can be public. A host that is not in the list is not a place the grant can land.
- No deploy after editing the TOML. The edit only exists on your disk. Shopify's own words: for configuration changes to take effect for all stores in production, you need to run the deploy command.
- automatically_update_urls_on_dev left on. The next
app devagainst that config updates its app URL and redirect URLs to the generated ones. - No config use afterwards. Your default config is still production, so the next dev session starts there.
The order that works
- Link a production config:
shopify app config link. - Edit the lines above and read them back once.
- Set the environment variables and the database on your host.
- Deploy the configuration:
shopify app deploy --config production. - Build and start the web app on the host.
- Install the app on a development store from the Dev Dashboard and open it. That is the test.
- Run
shopify app config useand pick your development config.
Want to look before it goes live?
Deploy releases the new version straight away. shopify app deploy --no-release creates the version without releasing it, so merchants do not get it. You can release it later with shopify app release or from the Dev Dashboard. The Events subscription post uses the same flag to check a configuration change before it reaches anyone.
Scaffolding the app in the first place? The Homebrew install of the CLI needs one flag.
Learning Shopify app development with AI writing the code?
The path teaches the fundamentals. Start the Shopify app development path.
Frequently asked questions
Which lines in shopify.app.toml change when moving to production hosting?
application_url becomes your host's URL, [auth] redirect_urls gets your host's URL plus your callback path (the React Router template uses /auth/callback), and [build] automatically_update_urls_on_dev is set to false, which Shopify recommends for production apps. Any other absolute URLs in the file, such as an app proxy URL, change too. Then run shopify app deploy so the changes reach production.
Does shopify app deploy deploy my web app?
No. It builds your app configuration and extensions and releases them as a new app version. Your web app goes on your hosting provider separately.
Should I use a separate Shopify app for production?
Yes, Shopify recommends it. The production app can share the repository and code with your development app but has its own record and configuration in the Dev Dashboard. Link it with shopify app config link and select it with --config or shopify app config use.
Which environment variables does a hosted Shopify app need?
SHOPIFY_APP_URL (the deployed URL with protocol), SHOPIFY_API_KEY (the client ID) and SHOPIFY_API_SECRET are required. SCOPES is optional with Shopify-managed installation, and PORT defaults to 3000. shopify app env show prints the values for your linked app.
How do I create an app version without releasing it?
Run shopify app deploy --no-release. It creates the version but does not make it available to merchants. Release it later with shopify app release or from the Dev Dashboard.
What does automatically_update_urls_on_dev do?
When it is true, shopify app dev updates your app URL and redirect URLs automatically, which suits the built-in tunnel in development. When it is false, your URLs are not updated on dev, which Shopify recommends for production apps. When the setting is omitted, the CLI asks you to choose.
- app-development
- shopify-cli
- deployment
- hosting
About the author
Bas Lefeber, Founder, learnshopify.dev
Bas builds learnshopify.dev, where developers learn production-grade Shopify theme development against a live storefront. He writes about Liquid, theme architecture, and the parts of the job that still matter now that AI writes the code.
Keep going in the curriculum

