Skip to content
littleworksdocs

Explore the documentation

Meet LittleworksA little backend for what you’re building on Shopify.Littleworks or your own appWhat it takes to give a Shopify feature a backend: with Littleworks, or with a custom app you build and run yourself.Connect to LittleworksChoose the CLI, a plugin, or a remote MCP connection.CLIConnect from your terminal with Shopify approval and no manual tokens.Claude pluginThe Littleworks MCP connection and agent guidance in one package.OpenAI pluginThe Littleworks MCP connection and agent guidance in one package.MCP with OAuthConnect a compatible client directly, without a marketplace plugin.Build with an agentThe operating guide for agents building on Shopify with Littleworks.Write a workA JavaScript handler, a small manifest, and a version you test and then publish.Keep secretsEncrypted credentials, shared across your store’s works.Call external servicesMake public HTTPS API requests from a work using http.fetch().Store dataDocument collections with a small API, scoped automatically to the work that uses them.Call ShopifyCall Shopify’s Admin and Storefront GraphQL APIs with credentials held by Littleworks.Store filesKeep uploads such as artwork and photos in the merchant’s Shopify Files, uploaded by the browser straight to Shopify.Expose an endpointConnect an existing frontend to a work through a small JSON API.Customer access and invitationsRequire a signed-in shopper or a narrow, expiring invitation before a work runs.RecipesUseful things to build for your store, with the backend already taken care of.Product reviewsCollect customer reviews, verify purchases, and publish approved content directly into your Shopify theme.Customer wishlistsGive signed-in customers a persistent list of products they can revisit across devices.Customer quote requestsCollect a customer’s products, quantities, and requirements without turning a request into an order.Back-in-stock alertsCollect confirmed signups on sold-out variants, email them through your own provider when stock returns, and see every signup and send in your admin.Transactional emailSend email from your works through your own provider, never twice for the same thing, and see what was sent and what failed.Build a merchant pageDescribe your records and what merchants do with them; Littleworks renders a native Shopify admin page.Run works on their ownRun a work when something happens in the store, on a schedule, or from a Shopify Flow workflow.Run background jobsQueue runs for later or in the background: fan out to thousands of customers, import in pages, follow up days later, and retry what fails.MCP tool referenceTools to inspect, deploy, run, and organize the backend for a connected store.Usage and allowancesSee what your works use, how much capacity remains, and when allowances reset.Inspect and troubleshootFind the relevant run, understand the failure, and make the next change deliberately.Limits and securityThe current runtime boundaries, data isolation model, and execution allowances.
Shopify admin
Build
Markdown

Write a work

A JavaScript handler, a small manifest, and a version you test and then publish.

A work has two parts: source code and a manifest describing its input, entry point, permissions, and data scope. The examples below illustrate the interface; deploy them only as part of an authorized build or change.

Write the handler

Export one default async function. Littleworks supplies input, db, shopify, secrets, http, auth, cache, context, and log. cache.purge(work) clears a cached work’s responses after a write. Return a JSON-compatible value or Response.json(body, { status }).

notes.save.js
export default async ({ input, db }) => {
  const notes = db.collection("notes");

  const note = await notes.create({
    message: input.message,
    status: "new",
  });

  return { id: note.id };
};

This example stores a note and returns its ID. It has no public endpoint and does not use Shopify. The manifest validates the message before the handler runs.

Describe the work

Manifest
{
  "name": "notes.save",
  "title": "Save a note",
  "feature": "notes",
  "trigger": {
    "type": "callable"
  },
  "permissions": {
    "shopify": false
  },
  "inputSchema": {
    "type": "object",
    "properties": {
      "message": {
        "type": "string",
        "minLength": 1,
        "maxLength": 1000
      }
    },
    "required": [
      "message"
    ],
    "additionalProperties": false
  }
}
FieldPurpose
nameStable work identifier, such as notes.save. Lowercase letter first, then lowercase letters, digits, dots, underscores, or hyphens; up to 80 characters.
titleMerchant-facing name, up to 100 characters. Optional description is limited to 400 characters.
featureData namespace shared by related works. Fixed by the work’s first version; keep it unchanged when deploying again.
triggerPrivate callable, or an explicit HTTP GET or POST entry point.
permissions.shopifyWhether this work can use the Shopify GraphQL client.
inputSchemaJSON Schema checked before execution. Declare required properties and reject unexpected fields where appropriate.
runtimeOptional. The current supported profile is portable-js-v1.

Deploy, test, publish

A work is a draft, published or paused. It keeps every version you deploy, and exactly one version is current. The rule that ties it together: draft things run the newest version; published things run the current version.

StatusWhat runs
DraftNothing real. Test runs use the newest version, which is also current.
PublishedThe current version serves real traffic: endpoints, the app proxy, published pages and invocations without a version. A newer, pending version can be tested alongside it.
PausedA published work switched off. Real runs are refused with FUNCTION_PAUSED until it is resumed or published; test runs still work.

Call deploy_function with { manifest, source }. Pass the full manifest object and handler source string. Every deployment saves a new immutable version. On a draft it becomes current immediately. On a published or paused work it is saved as a pending version and the current version keeps serving; the response says which version is current.

invoke_function arguments
{
  "name": "notes.save",
  "input": {
    "message": "A test note"
  },
  "idempotencyKey": "notes-save-test-001"
}

invoke_function runs a draft’s newest version as a test run. On a published work it runs the current version for real; pass version to test the pending version or any other one. The response includes test and the version that ran. Choose a new idempotency key for each intentional invocation. Reusing a key prevents replay with a conflict response; it does not return the original result. Use read_collection to inspect the note and list_runs to find the execution.

RunReal or test
Real URL, app proxy, published pageReal: the current version of a published work
invoke_function on a published work, without a version or with the current oneReal
invoke_function on a draft, or with any other versionTest
Preview URL, draft pageTest: the newest version
invoke_function on a page workTest, at any version; page works run for real only from their published page

Publish, change and roll back

publish_function with { name, version? } makes a version current and the work published, when the merchant’s instructions authorize it. version defaults to the newest. Before publishing, tell the merchant how many test records remain and ask whether to delete them with delete_test_records; leftover test records can conflict with real saves under a uniqueness rule.

To change a published work, deploy again: the new version waits as pending while customers keep using the current one. Test it by passing its version, then publish it. Publishing an earlier version is a rollback. Publishing a paused work also resumes it; set_function_state pauses and resumes a published work without changing its current version. Drafts cannot be paused, because they take no real traffic.

Keep the source self-contained

MCP accepts JavaScript ES modules without imports or TypeScript syntax. It does not install dependencies or run a hosted build. The CLI can bundle compatible source locally before deployment. Packages cannot bypass the runtime’s network or capability restrictions.

The context contains storeId, shop, runId, test (true for test runs), and mode. Credentials and provider database bindings are never passed to your code. See Limits and security.