Back to Blog
Tutorial10 min read2026-07-05

How to Deploy Vendure E-commerce Backend

Vendure is a TypeScript/Node headless commerce framework. Learn how to deploy its server and worker processes with PostgreSQL and persistent asset storage on a managed cloud.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Vendure is a headless commerce framework built on Node.js, TypeScript, and NestJS, with a GraphQL API. It sits in a sweet spot: more code-first and lightweight than Saleor, more structured than rolling your own. Like most serious commerce platforms, a production Vendure deployment is two processes — a server and a worker — backed by a database. Here's how to ship it.

Vendure's process model

Vendure splits responsibilities cleanly:

  • Server process — handles the Shop and Admin GraphQL APIs and HTTP traffic.
  • Worker process — runs the job queue (order processing, email, search indexing, etc.).

Both run from the same codebase. By default Vendure can run the worker in the same process, but for production you should run them separately so you can scale and restart them independently.

Step 1: Configure the database

Vendure uses TypeORM and supports PostgreSQL, MySQL/MariaDB, and SQLite. Use PostgreSQL in production. In vendure-config.ts:

import { VendureConfig } from '@vendure/core';

export const config: VendureConfig = {
  apiOptions: {
    port: +(process.env.PORT || 3000),
    adminApiPath: 'admin-api',
    shopApiPath: 'shop-api',
  },
  dbConnectionOptions: {
    type: 'postgres',
    url: process.env.DATABASE_URL,
    synchronize: false, // never true in production
    migrations: ['./migrations/*.+(js|ts)'],
  },
  // ...
};

Set synchronize: false and rely on migrations. Auto-sync in production will eventually corrupt your schema.

Step 2: Generate and run migrations

Vendure has a built-in migration generator. During development:

npx vendure migrate

This creates timestamped migration files. Commit them. On deploy, run migrations before the server starts. A clean pattern is a package.json script:

{
  "scripts": {
    "start:server": "node ./dist/index.js",
    "start:worker": "node ./dist/index-worker.js",
    "migrate": "node ./dist/migrate.js"
  }
}

Vendure's project scaffold generates index.ts, index-worker.ts, and a migration entrypoint for exactly this purpose.

Step 3: Deploy the server

On PandaStack, Vendure deploys cleanly as a Node container app — no Dockerfile required, since buildpacks auto-detect Node.

  1. 1Provision a managed PostgreSQL database (PostgreSQL 16.x works well).
  2. 2Create a container app linked to your repo. Link the database; DATABASE_URL is injected.
  3. 3Set the build command to npm run build and the start command to npm run start:server.
  4. 4Add a release/pre-deploy step that runs npm run migrate so schema changes apply once per deploy.

Live build logs let you watch the TypeScript compile and the server boot.

Step 4: Deploy the worker

Create a second container app from the same repo with start command npm run start:worker. It needs the same DATABASE_URL and any shared secrets, but no public port — it's a background process pulling from the job queue.

ProcessStart commandPublic?Scales on
Serverstart:serverYesHTTP/GraphQL load
Workerstart:workerNoJob queue depth

Step 5: Persistent asset storage

Vendure's AssetServerPlugin stores product images. The default local storage strategy writes to disk — fine for dev, lost on container restart. For production, use an S3-compatible backend:

import { AssetServerPlugin, configureS3AssetStorage } from '@vendure/asset-server-plugin';

AssetServerPlugin.init({
  route: 'assets',
  assetUploadDir: '/tmp/assets',
  storageStrategyFactory: configureS3AssetStorage({
    bucket: process.env.S3_BUCKET!,
    credentials: {
      accessKeyId: process.env.S3_ACCESS_KEY!,
      secretAccessKey: process.env.S3_SECRET_KEY!,
    },
    nativeS3Configuration: {
      endpoint: process.env.S3_ENDPOINT,
      forcePathStyle: true,
      region: process.env.S3_REGION,
    },
  }),
});

A self-hosted MinIO instance works as the S3 backend if you want everything in one place.

Step 6: Search

Vendure's DefaultSearchPlugin uses the database and is fine for modest catalogs. For larger stores, swap in the Elasticsearch plugin. If you go that route, point it at a dedicated search cluster rather than overloading your primary database.

Production checklist

  • synchronize: false and committed migrations.
  • Server and worker as separate apps sharing one database.
  • S3-compatible asset storage, not local disk.
  • Strong superadmin credentials and a stable cookie/session secret.
  • Database connection pooling if you run multiple server replicas.

Honest caveats

Vendure is younger than Magento or Shopify's ecosystem, so you'll find fewer off-the-shelf plugins. But the plugin API is excellent and the codebase is approachable TypeScript. For teams comfortable writing code, that trade is usually worth it.

Wrapping up

Vendure rewards a clean two-process deployment: a server for the API and a worker for jobs, both pointed at managed PostgreSQL with S3 asset storage. Get migrations and asset storage right and the rest is standard Node operations.

PandaStack auto-detects Node, injects DATABASE_URL from a linked database, and lets you run server and worker as independent apps — the free tier covers a dev store. Start at https://dashboard.pandastack.io.

References

  • Vendure documentation: https://docs.vendure.io/
  • Vendure deployment guide: https://docs.vendure.io/guides/deployment/deploying-to-production/
  • Vendure migrations: https://docs.vendure.io/guides/developer-guide/migrations/
  • AssetServerPlugin S3 storage: https://docs.vendure.io/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy/
  • TypeORM docs: https://typeorm.io/

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also