Skip to Content
Deployment

Deployment

This page covers deploying Shipmore Core to Railway and Vercel. Both platforms support Next.js apps; the main differences are database provisioning and how custom domains work for multi-tenant setups.

Before you deploy

  1. Generate types — if you changed any Payload collections or globals, run pnpm run generate:types and pnpm run generate:importmap so types and admin components are in sync.
  2. Environment variables — have your production values ready (see Environment Setup). At a minimum you need PAYLOAD_SECRET, DATABASE_PUBLIC_URI, DATABASE_PRIVATE_URI, STRIPE_SECRET_KEY, and STRIPE_WEBHOOKS_ENDPOINT_SECRET.
  3. MongoDB — you need a production MongoDB instance. MongoDB Atlas  (free tier available) is recommended. Create a cluster, get the connection string, and use it for your DATABASE_* vars.
  4. S3 storage — local file storage is ephemeral on both Railway and Vercel. For production, set up S3 (or an S3-compatible service) so media uploads persist. See Storage.

Build and start

pnpm build # builds the Next.js + Payload app (includes /docs) pnpm start # starts the production server

If the build runs out of memory, increase the heap size:

NODE_OPTIONS=--max_old_space_size=8192 pnpm build

For CI/Docker where not all env vars are available at build time:

SKIP_ENV_VALIDATION=1 pnpm build

Railway

Railway  runs your app as a long-running Node.js service with persistent storage and easy database provisioning.

1. Create a project

  1. Sign in to railway.app  and create a New Project.
  2. Choose Deploy from GitHub repo and select your Shipmore Core repository.
  3. Railway auto-detects the Node.js/Next.js framework.

2. Add MongoDB

Option A — Railway MongoDB service:

  • In your project, click NewDatabaseMongoDB.
  • Railway provisions a MongoDB instance and gives you a connection string.
  • Copy the connection string for your env vars.

Option B — MongoDB Atlas (recommended for production):

  • Use your Atlas connection string. Ensure the Atlas cluster allows connections from Railway’s IP ranges (or allow all IPs: 0.0.0.0/0 with strong credentials).

3. Set environment variables

In your Railway service, go to Variables and add:

VariableValue
PAYLOAD_SECRETA long random string
DATABASE_PUBLIC_URIYour MongoDB connection string
DATABASE_PRIVATE_URISame connection string (or Railway’s internal URL if using their MongoDB)
NEXT_PUBLIC_SERVER_URLhttps://your-domain.com (your production URL)
STRIPE_SECRET_KEYsk_live_... or sk_test_...
STRIPE_WEBHOOKS_ENDPOINT_SECRETwhsec_... (from Stripe dashboard)
PORT3000 (Railway uses this to route traffic)

Add S3, email, and auth vars as needed (see Environment Setup).

4. Build and start settings

Railway typically auto-detects the build/start commands. If not, set them in Settings:

  • Build command: pnpm install && pnpm build
  • Start command: pnpm start

If the build runs out of memory, prepend NODE_OPTIONS=--max_old_space_size=8192 to the build command or set it as an environment variable.

5. Custom domains

  1. In your Railway service, go to SettingsNetworkingCustom Domain.
  2. Add your domain (e.g. mysite.com).
  3. Railway gives you a CNAME target. Set a CNAME record in your DNS provider pointing your domain to Railway’s target.
  4. Once DNS propagates, create a tenant in Payload with domain mysite.com.

6. Multiple tenant domains

For each additional tenant domain:

  1. Add the domain as a Custom Domain in Railway (same service).
  2. Set the DNS CNAME record for that domain.
  3. Create a tenant in Payload with that domain.

Railway routes all custom domains to the same service; the app’s host-based rewrite handles tenant resolution.

7. Stripe webhooks

In the Stripe Dashboard , create an endpoint:

  • URL: https://your-domain.com/api/webhooks/stripe
  • Events: checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted, price.created, price.updated, price.deleted

Copy the signing secret and set it as STRIPE_WEBHOOKS_ENDPOINT_SECRET in Railway.


Vercel

Vercel  deploys Next.js apps as serverless functions with edge CDN. It works well for Shipmore Core with a few considerations.

1. Import project

  1. Go to vercel.com/new  and import your GitHub repository.
  2. Vercel auto-detects Next.js as the framework.
  3. Set the Root Directory if your repo has a monorepo structure (usually not needed for Shipmore Core).

2. Set environment variables

In your Vercel project, go to SettingsEnvironment Variables and add the same required vars:

VariableValue
PAYLOAD_SECRETA long random string
DATABASE_PUBLIC_URIYour MongoDB Atlas connection string
DATABASE_PRIVATE_URISame (or Atlas private endpoint if available)
NEXT_PUBLIC_SERVER_URLhttps://your-domain.com
STRIPE_SECRET_KEYsk_live_... or sk_test_...
STRIPE_WEBHOOKS_ENDPOINT_SECRETwhsec_...

If the build fails on missing env vars, add SKIP_ENV_VALIDATION=1 for the Build environment only.

3. Build settings

Vercel’s defaults work for most cases:

  • Build command: pnpm build (auto-detected)
  • Output directory: .next (auto-detected)
  • Install command: pnpm install (auto-detected)

For memory issues, override the build command:

NODE_OPTIONS=--max_old_space_size=8192 pnpm build

4. Important: media storage

Vercel’s filesystem is ephemeral — files written at runtime (e.g. media uploads) are lost between deployments and across serverless function invocations. You must use S3 storage for media in production on Vercel. See Storage.

5. Custom domains

  1. In your Vercel project, go to SettingsDomains.
  2. Add your domain (e.g. mysite.com).
  3. Vercel provides DNS configuration instructions (A record or CNAME).
  4. Create a tenant in Payload with domain mysite.com.

6. Multiple tenant domains

On Vercel, every tenant domain must be added as a custom domain in the project settings. Vercel only routes traffic to your app for domains it knows about.

For each additional tenant:

  1. Add the domain in Vercel’s Domains settings.
  2. Configure DNS for that domain.
  3. Create a tenant in Payload with that domain.

The app’s host-based rewrite handles tenant resolution from there.

7. Stripe webhooks

Same as Railway — create a webhook endpoint in the Stripe Dashboard pointing to https://your-domain.com/api/webhooks/stripe and set the signing secret in Vercel’s env vars.


Post-deployment checklist

  • App is running and /admin is accessible
  • First admin user created (or existing user can log in)
  • At least one tenant created with the production domain
  • Tenant’s frontend loads at the custom domain
  • S3 storage is configured and media uploads work
  • Stripe webhook endpoint is set and verified (send a test event from Stripe Dashboard)
  • Email is configured if using newsletter or transactional emails
  • NEXT_PUBLIC_SERVER_URL matches your production URL