Skip to content

Project structure

openshop init creates the app definition, sample provider and flow, Shopify configuration, package scripts, deployment files, and an initial migration. Create optional feature directories as your app needs them.

  • Directoryproviders/
    • warehouse.ts
  • Directoryflows/
    • syncOrders.ts
  • Directorydrizzle/
    • …
  • openshop.app.ts
  • openshop.config.ts
  • drizzle.config.ts
  • shopify.app.toml
  • shopify.web.toml
  • package.json
  • Dockerfile
  • ecosystem.config.cjs
Optional directory Add it when you need
proxy/ Storefront or Customer Account endpoints
routes/ HTTP endpoints with explicit authentication
webhooks/ Registered Shopify event handlers
models/ Application-owned database tables
admin/pages/ Experimental custom admin screens
tests/ An app test suite; openshop test requires tests/bootstrap.ts

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, MCP config, and admin page visibility 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 optional public server routes mounted under /routes/*. Every route must explicitly declare an authentication function or auth: 'none'.

Contains experimental app-owned Preact pages. A page.tsx file defines a filesystem route, while a colocated actions.server.ts defines authenticated, typed loaders and actions. See Custom admin pages.

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",
"#routes/*": "./routes/*.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.