Skip to main content

CLI Setup

The LaunchMyStore CLI (lms) helps you create, develop, test, and deploy apps, extensions, and functions from the command line. The CLI is a Node 18+ ESM package that talks to the LaunchMyStore API and signs webhooks locally for end-to-end development.
@launchmystore/cli@2.0.3 is live. Functions compile to WASM on your machine using Bytecode Alliance Javy; the server only validates that uploads are Javy dynamic-mode modules — it never runs your source through a compiler. lms extension push -t now accepts the developer-friendly type names emitted by lms extension generate (theme_block, function_payment, etc.) and maps them to the canonical upload types automatically.

Installation

Requires Node.js 18 or higher. To build functions you’ll also need Javy v3+ on your PATH (or pointed to by the JAVY_BIN_PATH environment variable).
npm install -g @launchmystore/cli
Verify the install:
lms --cli-version
The flag is --cli-version (not --version) so it doesn’t collide with the subcommand-level --version <semver> flag used by lms app version and lms app deploy.
If lms is not on your PATH after a global install, see the troubleshooting section at the bottom of this page.

Authentication

The CLI authenticates with email and password and stores a refreshable credential bundle in ~/.lms/credentials.json (override the directory with the LMS_CONFIG_DIR environment variable).
lms auth login --email you@example.com --api-base https://api.launchmystore.io
Inspect or end the session:
lms auth whoami
Treat ~/.lms/credentials.json like an SSH key — it contains a long-lived refresh token. Don’t commit it or share it.

Project Configuration

After you scaffold an app, the CLI walks up from your current working directory looking for a .lmsrc.json file. This file binds the local project to a specific app in the developer dashboard so subsequent commands know which app they’re operating on.
.lmsrc.json
{
  "appId": "app_abc123",
  "handle": "my-awesome-app",
  "name": "My Awesome App",
  "clientId": "cli_xyz789",
  "scopes": ["read_products", "write_products"]
}
Most app/extension/function/webhook/billing commands accept an --app flag to target a specific app explicitly. Without it, they fall back to the appId in the nearest .lmsrc.json.

Quickstart

1

Sign in

lms auth login --email you@example.com --api-base https://api.launchmystore.io
2

Create an app

Pick a template (node, react, or extension-only). The CLI registers the app, scaffolds the project, and writes .lmsrc.json + .env.
lms app create --name "My Awesome App" --handle my-awesome-app
3

Install dependencies

cd my-awesome-app
npm install
4

Run the dev server with a tunnel

lms app dev
This starts your local server, opens a Cloudflare tunnel, watches extensions/, and PATCHes the app’s redirect URLs to point at the tunnel.

Templates

lms app create can scaffold one of three starter templates. Pass --no-template to skip scaffolding and only register the app remotely.
TemplateWhat you get
nodeNode + Express server with /auth/callback and /webhooks routes
reactVite + React, wrapped in @launchmystore/app-bridge-react’s AppBridgeProvider
extension-onlyNo backend — just an extensions/blocks/example/ skeleton for theme/checkout extensions

Commands Reference

Auth

CommandDescription
lms auth login --email <email> --api-base <url>Email/password login. Writes ~/.lms/credentials.json
lms auth logoutClear stored credentials
lms auth whoamiShow the currently signed-in developer

App

CommandDescription
lms app create [--name] [--handle] [--no-template] [--force]Register an app via POST /apps/developer/create, optionally scaffold a template
lms app listList apps you own
lms app info [appIdOrHandle]Show details for one app (defaults to the project’s .lmsrc.json)
lms app dev [--port 3000] [--cmd "npm run dev"] [--watch <dir>] [--no-tunnel] [--no-update-urls]Run local dev server, open a Cloudflare tunnel, watch extensions/, update redirect URLs
lms app deploy --version <semver> [--app] [--notes <text>] [--notes-file <path>] [--no-publish]Wraps version create + version publish in one step
lms app rollback <installationId> <targetVersion>Roll a single installation back; pins the install and disables auto-update
lms app resume-auto-update <installationId>Re-enable auto-update on a pinned installation

App Versions

CommandDescription
lms app version create --version <semver> [--app] [--notes <text>] [--notes-file <path>]Create a new version
lms app version publish <version> [--app]Publish a created version
lms app version deprecate <version> [--app]Mark a version as deprecated
lms app version list [--app]List all versions
lms app version stats [--app]Show install + rollout stats

Function

CommandDescription
lms function build -f src/function.js -o dist/function.wasm [--emit-wrapped <dir>]Compile a JavaScript function to a Javy dynamic-mode .wasm artifact, locally
lms function test [-f src/function.js | --wasm <path>] [-t <type>] [--input <json>] [--input-file <path>] [--timeout <ms>]Run a function against the hosted sandbox. Compiles locally first unless --wasm is given
lms function deploy [--app] [-f src/function.js | --wasm <path>] [-h <handle>] [-t <type>] [--fallback skip|fail]Build (if needed) then upload a pre-built .wasm artifact and register the handle
lms function list [--app]List functions registered for the app
lms function logs <handle> [--app] [--limit] [--page]Tail/page execution logs for a function

Extension

lms extension generate is a local-only scaffolder. Functions are written to functions/<handle>/ and all other extension types to extensions/<handle>/.
CommandDescription
lms extension generate [-t <type>] [-h <handle>] [--dir <path>]Scaffold an extension locally. Types: theme_block, storefront_snippet, checkout_ui, post_purchase, admin_block, function_shipping, function_payment, function_delivery, function_cart_transform, function_order_validation, function_discount
lms extension list [--app]List extensions registered to the app
lms extension push --name --handle --type --target --path [--update] [--app]Multipart upload of files. Types: app_block, theme_embed, admin_block, checkout_extension, app_script, app_function
lms extension remove <handle> [--app]Remove an extension from the app

Webhook

CommandDescription
lms webhook list [--limit] [--page] [--status] [--topic]List webhook deliveries with filtering
lms webhook retry <deliveryId>Re-send a single delivery
lms webhook trigger <topic> [--url <url>] [--port 3000] [--secret] [--payload <json>] [--payload-file <path>]Generate a sample payload, sign with HMAC-SHA256, POST to a local URL

Billing

CommandDescription
lms billing list [--app] [--status] [--limit] [--page]List subscriptions / charges for the app
lms billing summaryAggregate revenue summary across your apps
lms billing pricing --monthly <amount> --yearly <amount> [--app] [--currency USD]Set pricing in major units (e.g. 9.99); converted to cents server-side

Versioning

Use the app version subgroup to ship releases. The CLI separates create (uploads the artifact + metadata) from publish (makes it available to merchants), so you can stage a build and review it before promoting.
lms app version create --version 1.2.0 --notes-file CHANGELOG.md
lms app version publish 1.2.0
If you want both steps in one command, use lms app deploy --version 1.2.0. For the full lifecycle — auto-update channels, deprecation policy, rollback — see App Versioning.

Local Function Compilation

Functions ship as Javy dynamic-mode WASM modules. Your JavaScript is compiled on your machine into a tiny stub (typically 1–4 KB) that links against a shared QuickJS runtime (“provider”) at execution time — so each compiled function only carries your code, not a copy of the runtime. The server never runs your source through a compiler. It receives a pre-built .wasm, validates the import section to confirm it’s a Javy dynamic-mode build, then stores it.

Build a function

lms function build -f src/discount.js -o dist/discount.wasm
Optional flags:
FlagDescription
--emit-wrapped <dir>Write the wrapped source the CLI handed to Javy. Handy for debugging compile errors.
If javy isn’t on your PATH, point at it explicitly:
JAVY_BIN_PATH=/opt/javy/javy lms function build -f src/discount.js -o dist/discount.wasm

Test against the sandbox

lms function test either compiles locally first (-f) or uploads a pre-built artifact (--wasm), then runs it against the hosted sandbox without persisting anything. The fastest way to iterate.
# Compile from source on every run
lms function test -f src/discount.js -t discount \
  --input-file fixtures/cart.json --timeout 5000

# Or test an already-built artifact
lms function test --wasm dist/discount.wasm -t discount \
  --input-file fixtures/cart.json
Valid types: discount, shipping_rate, payment_customization, order_validation, cart_transform, delivery_customization.

Deploy to your app

# Build + upload in one step
lms function deploy -f src/discount.js -h save-10 -t discount

# Upload a pre-built artifact (skip the local build)
lms function deploy --wasm dist/discount.wasm -h save-10 -t discount

Function source contract

Export a run (or main) function that takes the input object and returns the output object — the CLI wraps your source with the stdin/stdout bridge expected by Javy:
// src/discount.js
export function run(input) {
  if (input.cart.totalPrice >= 100) {
    return {
      discounts: [
        { title: 'Spend $100, save 10%', value: 10, valueType: 'percentage', target: 'order' }
      ]
    };
  }
  return { discounts: [] };
}
The wrapper also accepts module.exports = fn, function main(input) {}, or exports.default = fn for compatibility with different bundler outputs.

Size limits

LimitDefaultOverride env
JavaScript source64 KBLMS_FUNCTION_MAX_SOURCE_SIZE
Compiled WASM256 KBLMS_FUNCTION_MAX_COMPILED_SIZE
A typical discount function compiles to ~3 KB. If you’re approaching the 256 KB cap you’re probably bundling unnecessary dependencies — strip them out rather than asking for a higher cap.

Local Webhook Testing

The CLI can simulate the production webhook dispatcher locally. It generates a realistic sample payload for the topic, signs it with HMAC-SHA256 using your client secret, and POSTs it to your local URL with the same headers your production server will receive: X-LMS-Topic, X-LMS-Webhook-Id, X-LMS-Delivery-Attempt, X-LMS-Hmac-SHA256.
lms webhook trigger orders/create \
  --url http://localhost:3000/webhooks \
  --secret $LMS_CLIENT_SECRET
If you don’t pass --secret, the CLI falls back to the LMS_CLIENT_SECRET environment variable.
Supported topics (38 total):
orders/create, orders/updated, orders/paid, orders/cancelled, orders/fulfilled,
products/create, products/update, products/delete,
customers/create, customers/update, customers/delete,
collections/create, collections/update, collections/delete,
carts/create, carts/update,
themes/publish, themes/update,
app/installed, app/uninstalled,
fulfillments/create, fulfillments/update,
discounts/create, discounts/update, discounts/delete,
blogs/create, blogs/update, blogs/delete,
checkouts/create, checkouts/update,
refunds/create, inventory/update, shop/update,
newsletter/create, contact_form/create,
customers/data_request, customers/redact, shop/redact

Configuration

The CLI reads project config from .lmsrc.json and credentials from ~/.lms/credentials.json. You can override the credentials directory globally with LMS_CONFIG_DIR — useful for keeping work and personal accounts separate, or for sandboxing CI.
LMS_CONFIG_DIR=~/.lms-staging lms auth login --email ci@example.com \
  --api-base https://staging.api.launchmystore.io

Environment Variables

VariableDescription
LMS_API_BASEOverride the default API base (https://api.launchmystore.io)
LMS_CONFIG_DIROverride the credentials directory (default ~/.lms/)
LMS_CLIENT_SECRETFallback HMAC secret used by lms webhook trigger when --secret is omitted
JAVY_BIN_PATHAbsolute path to the javy binary if it isn’t on your PATH
LMS_FUNCTION_MAX_SOURCE_SIZEOverride the JavaScript source size cap (default 65536)
LMS_FUNCTION_MAX_COMPILED_SIZEOverride the compiled WASM size cap (default 262144)
PORTForwarded into npm run dev from lms app dev

Troubleshooting

Make sure your npm global bin directory is on your PATH:
npm config get prefix
# Add {prefix}/bin (or {prefix} on Windows) to your PATH
On macOS with Homebrew Node, this is usually /opt/homebrew/bin. On Windows, it’s typically %APPDATA%\npm.
Long-lived sessions can be invalidated by a password change or admin revoke. Re-authenticate:
lms auth logout
lms auth login --email you@example.com --api-base https://api.launchmystore.io
lms auth login succeeds against any account on the platform — but the developer endpoints under /apps/developer/* require (a) a merchant account (not a storefront customer account), and (b) that you’ve registered at least one app. A 401 from those endpoints almost always means one of these prerequisites is missing.Run these to diagnose:
lms auth whoami
lms app list
Likely causes, in order:
  1. You logged in with a storefront customer account. Only merchant accounts can register developer apps. Sign up at the LaunchMyStore admin and re-run lms auth login with the merchant email.
  2. You haven’t created an app yet. lms app info looks up an existing app — it doesn’t create one. Run:
    lms app create --name "My App" --handle my-app
    
    This registers the app server-side and writes .lmsrc.json in the current directory. After this, lms app info, lms extension push, and lms function deploy will work.
  3. You’re querying an app that belongs to a different account. The CLI scopes queries to the token in ~/.lms/credentials.json. Another developer’s app returns 401, not 404. Use lms app list to see only the apps you own.
If lms app list itself returns 401 after a fresh lms auth login, open a developer support ticket with the account email so we can enable developer access on our side.
Fixed in @launchmystore/cli@2.0.3 — the developer-friendly type names from lms extension generate (theme_block, storefront_snippet, checkout_ui, post_purchase, and all six function_* variants) now map automatically to the canonical upload types (app_block, checkout_extension, app_function). Upgrade with npm install -g @launchmystore/cli@latest and verify with lms --cli-version.
lms app dev uses the cloudflared package. Make sure port 3000 is free (or pass --port), and that no firewall is blocking outbound connections to Cloudflare. To run without a tunnel — for example when your dev server is already publicly reachable — pass --no-tunnel and --no-update-urls.
Most commands resolve the active app from .lmsrc.json walked up from cwd. If you’re outside the project directory, pass --app <handle> (or --app <appId>) explicitly.
lms function build calls out to the javy binary. Install it from the Javy releases page and either put it on your PATH or set JAVY_BIN_PATH to its absolute location. Verify with:
javy --version
The CLI requires Javy v3 or higher (dynamic-mode support).
The upload endpoint checks the WASM import section for the javy_quickjs_provider marker. Static-mode builds (which embed the runtime instead of linking against the shared provider) are rejected because they exceed the size cap by orders of magnitude. Always compile with javy compile -d — the lms function build command does this for you automatically.
lms webhook trigger uses HMAC-SHA256 with the client secret as the key, over the raw JSON body, and sends the result in the X-LMS-Hmac-SHA256 header (base64-encoded). Verify your server is hashing the raw request body, not a re-serialized version, and that you’re using the same client secret the CLI is loading from --secret or LMS_CLIENT_SECRET.

Use with Claude Code

If you use Claude Code, install the LaunchMyStore Claude Skill to let Claude route plain-English requests (“build a discount function”, “list my orders”, “add a hero section”) to the right CLI command, MCP tool, App Bridge action, or Aqua snippet.
/plugin marketplace add LaunchMyStore/skill
/plugin install launchmystore@launchmystore
Restart Claude Code, then try /launchmystore I want to build my first app. Source: github.com/LaunchMyStore/skill

Next Steps

Build Your First App

A complete walkthrough using the node template

App Versioning

Release, publish, deprecate, and roll back versions

Functions Overview

Build, test, and deploy custom function logic with the CLI

App Bridge

Embed your app in the LaunchMyStore admin