Features · Development
One binary, one database, one dependency
GoCommerce is a Go program with its admin compiled in, talking to one PostgreSQL. Everything else — payments, carriers, search, an AI agent — is a module you import, and the whole API is written down in OpenAPI.
- 550 documented REST operations
- 1 production dependency (pgx)
- 54 modules, compiled in only when imported
The shape of it
-
One binary and PostgreSQL
The API and the 93-screen Svelte admin compile into one binary with go:embed. No Node.js at runtime, no cgo; it cross-compiles for Linux, Windows and macOS, and a distroless Docker image is provided.
admin/embed.go · Dockerfile -
One production dependency
go.mod requires only the pgx PostgreSQL driver, and modules add no third-party dependencies — CI enforces it.
go.mod · AGENTS.md -
Headless REST, documented
550 operations — 289 in the core, the rest from modules — in OpenAPI 3.0.3, served at /doc and printed by gocommerce spec. The admin is itself a client of the same API.
core/openapi.json -
MIT, all of it
The licence covers the whole repository. There is no closed or paid edition.
LICENSE
Extending it
-
Modules, compiled inPartial
54 modules plug into a small set of ports; import one and it is in your binary. Narrower than a plugin store: modules are Go, compiled in, not installed at runtime.
core/ports.go · ext/ -
Signed webhooks
The webhooks module posts signed events to any public https URL, with retries and a delivery log. Go code can also subscribe in-process.
ext/webhooks · core/events.go -
Custom data
Fifteen core tables — products, variants, orders, carts, discounts, vendors and more — carry a free-form metadata object. Product attributes follow Shopify’s taxonomy, embedded in the binary, and can be filtered.
core/types.go · Metadata -
Admin screens from modulesPartial
A module adds an admin screen by describing a list and a form, gated by rights. Missing: shipping your own front-end code into the admin.
core/screens.go -
Any language
Anything that speaks JSON over HTTP can drive the API, and non-Go services receive events through signed webhooks.
core/openapi.json
Deploying it
-
A tested full-stack examplePartial
examples/kitcommerce-stack runs PostgreSQL, the engine built from the checkout, Svelte Commerce at a pinned commit and Caddy, started by docker compose up -d --build --wait. Its smoke test places a cash-on-delivery order through the shop, finds it through the admin API and replays it to show that no second order is made; CI runs it whenever the example or the Dockerfile changes. Missing: shopper sign-in, search, reviews, wishlists and online payment.
examples/kitcommerce-stack · .github/workflows/kitcommerce-stack.yml -
A store’s own domain, with HTTPS
In Settings › Domains a store adds its domain and copies the DNS records the panel shows. Once the domain is verified, the engine lets the proxy route it and get its certificate, through Caddy’s on-demand TLS check or Traefik’s HTTP provider, and never for a name that is not a store’s. A storefront serving many stores passes on its visitor’s domain in X-Store, so each domain shows its own shop.
core/domain_routing.go · core/storeresolve.go -
Several brands on one install
One database and one deployment can answer under several names, each on its own admin domain, listed in GOCOMMERCE_BRANDS. The panel shows the brand’s name and logo, and emails to staff carry its name. Each store belongs to one brand and answers at <slug>.<its base domain>; a person keeps one account and sees only that brand’s stores there.
core/brands.go · cmd/gocommerce/main.go
Running it
-
gocommerce doctor
Health checks of the stock ledger, refunds, returns, the event backlog, discounts, the API contract, sealed secrets and the brands list, from the command line (non-zero exit on failure), the admin or the API.
core/doctor.go -
Several instances, no coordination
Run more copies behind a load balancer: background work is claimed with FOR UPDATE SKIP LOCKED and migrations run under an advisory lock. Uploads live on local disk, so instances share a volume for them.
core/outbox.go · core/migrate.go -
Events that are never lost
Each event is written in the same transaction as the change it describes, delivered at least once with backoff, and parked after 12 failures on an Events screen where it can be retried.
core/outbox.go -
Rate limits only at the doors
Operator sign-in, password reset and sign-up are throttled, and each AI agent key has its own number of requests a minute. Nothing else is limited: your server and database set the ceiling.
core/superusers.go · core/agent_keys.go -
Pictures resized by the enginePartial
The engine answers Cloudflare Image Resizing’s URL shape, /images/<store>/cdn-cgi/image/width=320/<picture>, so a storefront’s srcset gets each picture at a set width from 160 to 1280 px, made once and cacheable for a year. Only the store’s own pictures are resized, with no new dependency. Missing: WebP, AVIF and GIF originals are sent as they are, and pictures only a module holds are not resized.
core/images.go -
A command-line toolPartial
serve, migrate, store, superuser, doctor, brands, secrets, spec, taxonomy, attributes and version. Missing: environments, data branching and scaffolding.
cmd/gocommerce/main.go
Security
-
Secrets sealed at rest
With GOCOMMERCE_SECRETS_KEY set, payment and provider keys, the copy of an API key and webhook signing secrets are stored sealed with AES-256-GCM, so a database dump holds ciphertext. The engine seals what was stored before on its own at start-up and moves what the previous key sealed to the new one, and gocommerce doctor counts any left readable.
core/secrets.go · core/secrets_seal.go -
Cost prices stay with the team
Only the store’s own team, not its marketplace sellers, sees a variant’s cost: in the panel, the admin API and MCP. Every public route leaves it out by default, a module’s included, and gctest.AssertPublicRoutesHideCost, run over every bundled module, fails if a public route shows it.
core/operator_view.go · gctest/public_cost.go -
Addresses a store sets must be public
A webhook endpoint, a provider’s API base URL or a search host typed by a store is checked when saved and again at every connection, redirects included; private and loopback addresses are refused unless the install sets GOCOMMERCE_ALLOW_PRIVATE_URLS, and doctor warns while it does.
core/outbound.go -
No keys in the notification log
Reading the log of sent emails and SMS shows password-reset and invitation links, codes and tokens as “(hidden)”, for every reader, the owner included. The messages themselves are unchanged, and a resend still works.
core/notification_credentials.go -
A trace id on every request
Each request gets an id, returned in X-Trace-Id and printed on its log line beside the store; a caller may send its own. AI jobs, model runs and proposals keep the id of the request that caused them.
core/trace.go
Working with AI agents
-
An MCP server
19 tools that call the same domain services as the API — never the database — each checked against the caller’s rights. Read-only mode withholds every tool that changes anything, an agent key is offered the read tools only, and changes are logged. Over HTTP or stdio.
ext/mcp -
An AI gateway
Every model call a store makes goes through one module, which holds it to the store’s own key, a monthly cap and the kinds of data its owner lets out, and records what it cost.
ext/ai-gateway -
Guides for coding agents
AGENTS.md sets 16 architectural rules and four notes for AI agents; skills/ holds 16 task guides and an index, so an agent reads the part of the domain it is about to change.
AGENTS.md · skills/ -
A test kit for module authors
gctest gives each test its own isolated database schema, and over a thousand tests catch a wrong edit.
gctest/gctest.go
Not in GoCommerce yet
Self-hosted, GoCommerce gives you standard PostgreSQL backups and point-in-time recovery rather than a hosted platform’s conveniences. Also absent today:
- Sandboxes and data branchingNo hosted environments; copy a store with pg_dump and pg_restore.
- Managed backups and auto-scalingBackups and scaling are yours, on your own infrastructure.
- GraphQLThe API is REST and JSON.
- Custom webhook payloadsEach event has a fixed body; you can filter events, not reshape them.
- An app storeThe Plugins screen configures modules already compiled in.
- A generated clientGenerate your own from the OpenAPI spec.
- Data anonymisationNo tooling to mask production data.
FAQ
Questions about development
What do I need to run GoCommerce?
One PostgreSQL database and somewhere to run one binary — a server, a container or your laptop. No Node.js, Redis or message broker is required.
Can I scale it horizontally?
Yes. Several instances can run behind a load balancer with no coordination between them; background work is claimed with row locks. Give them a shared volume for uploaded media, and size your PostgreSQL connection pooling.
How do I run GoCommerce and Svelte Commerce together?
Start from examples/kitcommerce-stack in the GoCommerce repository. Docker Compose runs PostgreSQL, the engine, Svelte Commerce and Caddy, and CI runs its smoke test, which places a cash-on-delivery order through the shop, whenever the example changes. It has no shopper sign-in, search or online payment yet.
Is there a GraphQL API?
No. The API is REST and JSON, documented in OpenAPI 3.0.3, so any language can generate a client from the spec.
How do I add a feature the core does not have?
Write a module: a Go package under ext/ that plugs into the core’s ports and is compiled in when imported. Or keep it outside GoCommerce entirely and listen to its signed webhooks.
Can an AI agent run the store?
Through the MCP module: 19 tools that go through the same services and rights checks as the API. Read-only mode lets an agent look without changing anything, and so does an agent key, which reaches the read tools only.
Read the code behind every tile
Each file named on this page is in the GoCommerce repository, MIT licensed. Run it and check.