Skip to content

Project structure

The minimal OpenShop template separates framework config, providers, flows, proxy routes, Shopify config, and database migrations.

  • Directoryproviders/
  • Directoryflows/
  • Directoryproxy/
  • Directorydrizzle/
  • openshop.app.ts
  • openshop.config.ts
  • drizzle.config.ts
  • shopify.app.toml
  • shopify.web.toml

Creates the typed OpenShop app with defineOpenShop(). Register providers here so their connector methods are available in flows.

Exports the default runtime config with app.defineConfig(). Register flows, crons, webhooks, Shopify Function UI definitions, worker settings, retry policy, and MCP config here.

Contains provider definitions. Providers define admin config fields and methods for external systems.

Contains background job definitions. Flows run in workers and can use checkpointed steps, Shopify clients, provider connectors, logs, and the database.

Contains file-based app proxy and Customer Account extension routes. Route files export app.defineProxy().

Contains committed SQL migrations owned by the app. The folder includes framework-owned tables and app model tables.

GraphQL codegen can create generated operation types and OpenShop operation bridge files. The template ignores these files by default.

The template uses Node package subpath imports in package.json for app-local aliases:

{
"imports": {
"#app": "./openshop.app.ts",
"#flows/*": "./flows/*.ts",
"#functions/*": "./functions/*.ts",
"#models/*": "./models/*.ts",
"#providers/*": "./providers/*.ts",
"#queries/*": "./queries/*.ts",
"#server/*": "./server/*.ts",
"#webhooks/*": "./webhooks/*.ts"
}
}

Use these aliases for imports that cross app folders:

import { app } from '#app'
import { syncOrders } from '#flows/syncOrders'
import { warehouse } from '#providers/warehouse'

Relative imports are still fine for files that live next to each other, such as test helpers in the same directory.