Build your first OpenShop app
This tutorial starts PostgreSQL, creates an OpenShop app from the minimal template, installs it on a development store, and runs the generated flow.
Prerequisites
Section titled “Prerequisites”- Node.js
>=26 <27 - pnpm
>=11 <12 - Docker, or another PostgreSQL 17 instance
- Shopify CLI
- A Shopify Partner account with a development store
Start PostgreSQL
Section titled “Start PostgreSQL”Create a local database container:
docker run --name openshop-postgres \ -e POSTGRES_DB=openshop \ -e POSTGRES_USER=openshop \ -e POSTGRES_PASSWORD=openshop \ -p 5432:5432 \ -d postgres:17-alpineOn later sessions, restart the same container with docker start openshop-postgres.
Create the app
Section titled “Create the app”pnpm dlx openshop init my-appcd my-apppnpm installThe template pins the same OpenShop version used to generate it. It also contains the app definition, config, sample provider, sample flow, Shopify TOML files, Drizzle config, and an initial migration.
Directoryproviders/
- …
Directoryflows/
- …
Directoryproxy/
- …
Directoryroutes/
- …
Directorydrizzle/
- …
- openshop.app.ts
- openshop.config.ts
- drizzle.config.ts
- shopify.app.toml
- shopify.web.toml
The template also defines package.json#imports aliases so app code can use package-private imports such as #app, #flows/syncOrders, #providers/warehouse, and #routes/ping instead of ../ paths.
Configure the local environment
Section titled “Configure the local environment”Create .env in the generated project:
printf '%s\n' \ 'DATABASE_URL=postgresql://openshop:openshop@localhost:5432/openshop' \ > .envopenshop dev loads this file without replacing variables already supplied by the process. .env is ignored by the generated Git configuration.
Apply the initial migration and confirm that no migration remains pending:
pnpm run db:migratepnpm run db:statusLog in and link the Shopify app
Section titled “Log in and link the Shopify app”Authenticate Shopify CLI:
shopify auth loginLink shopify.app.toml to an existing Partner Dashboard app, or create one when Shopify CLI prompts:
shopify app config linkSelect or create the app and organization you want to use. The generated TOML requests read_products and read_orders; Shopify CLI keeps the linked app configuration for later runs.
Start Shopify development
Section titled “Start Shopify development”pnpm run shopifyThis is the only development command needed for the embedded app. It runs shopify app dev, creates the development tunnel, updates the development URLs, and invokes pnpm run dev from [commands] in shopify.web.toml.
In turn, openshop dev:
- runs optional GraphQL code generation;
- pushes the development schema;
- starts the API, admin UI, worker, and cron scheduler;
- reloads the API when app files change.
Use pnpm run dev directly only when you deliberately do not need the Shopify tunnel, OAuth installation, or embedded admin context.
Verify it worked
Section titled “Verify it worked”- Press
pin Shopify CLI, or open the preview URL it prints. - Install the app on the selected development store.
- In Providers, configure
warehousewithhttps://example.comand any non-empty development API key. The generated provider only logs its push, so this smoke value does not call that URL. - In Flows, run
syncOrderswith:
{ "limit": 10 }The run should move from pending or running to completed. Its logs should contain “Orders synced”. A failure is also visible on the run page with its step logs; common causes are a missing app installation or the read_orders scope not being granted.
Run the project checks:
pnpm run lintThe generated template runs GraphQL codegen before TypeScript and ESLint checks.
Next steps
Section titled “Next steps”- Edit the sample provider in
providers/warehouse.ts. - Edit the sample flow in
flows/syncOrders.ts. - Read Define a provider and Define a flow.