Step 2 of 4

Deploy Your Store

Put your store online so customers can visit it. Vercel hosts your site for free with automatic HTTPS.

You'll need a free Vercel account, your keys from Step 1, and optionally a domain name · Estimated time: 15–25 min

1. Start the Deployment

There are two ways to get your code onto Vercel. Both end up in the same place — pick whichever suits you.

Option A — the one-click button (fastest)

The product README has a Deploy with Vercel button at the top. It clones the repository into your own GitHub account and shows you a form for the environment variables before the first build. The form pre-fills prompts for nine variables:

NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_DB_URL
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
STRIPE_SECRET_KEY
NEXT_PUBLIC_SITE_NAME
NEXT_PUBLIC_SITE_URL
CRON_SECRET

Everything else (email, file uploads, analytics) is added afterwards under Settings → Environment Variables. Section 2 below explains each value.

Option B — import an existing repository

Use this if you already pushed your own copy of the code to GitHub, GitLab, or Bitbucket.

  1. Go to vercel.com/new
  2. Click Import Git Repository (or Add New → Project)
  3. Find your ShipCommerce repository in the list and click Import
  4. Vercel will automatically detect that it's a Next.js project
  5. Expand Environment Variables and add the values from section 2 before you deploy

2. Add Your Environment Variables

Environment variables are configuration values your store reads when it starts — the database address, your site URL, payment keys. The block below is grouped so you can see what you have to fill in and what you can skip.

# ─── Required ───────────────────────────────────

# From Step 1 (Supabase)
NEXT_PUBLIC_SUPABASE_URL=https://abcdefghijk.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIs...
SUPABASE_DB_URL=postgresql://postgres:PASSWORD@...:6543/postgres

# Your store's name and public address
NEXT_PUBLIC_SITE_NAME=Your Store
NEXT_PUBLIC_SITE_URL=https://your-project.vercel.app

# Protects /api/cron/* — see section 4
CRON_SECRET=paste-a-64-character-hex-string-here

# ─── Payments (optional) ────────────────────────
# Added in Step 3. Cash on delivery and bank transfer
# work without these, so you can deploy first.

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_abc123...
STRIPE_SECRET_KEY=sk_live_abc123...
STRIPE_WEBHOOK_SECRET=whsec_abc123...

# ─── Optional ───────────────────────────────────

RESEND_API_KEY=re_abc123...             # order + account emails
RESEND_FROM_EMAIL=hello@yourstore.com   # defaults to onboarding@resend.dev
BLOB_READ_WRITE_TOKEN=vercel_blob_...   # image uploads; falls back to Supabase Storage

These are example values — use your own keys, not these.

How to add each variable: Type the name (e.g. NEXT_PUBLIC_SUPABASE_URL) in the "Name" field, paste your value in the "Value" field, then click Add. Repeat for each variable. Comments and blank lines are not part of a value — copy only the text after the = sign.

Generating CRON_SECRET

CRON_SECRET is a password you invent. It is the only thing standing between the public internet and your /api/cron/* routes, so use a random value rather than a word. On macOS or Linux:

openssl rand -hex 32

Copy the 64-character output into the CRON_SECRET value field. If you ran npm run setup locally, one was already generated for you — copy it out of your .env.local instead.

CRON_SECRET is required in production. Without it, the cleanup route refuses to run at all. Set it now even if you schedule the cron later.

What you can skip

  • Stripe keys — cash on delivery and bank transfer work out of the box. You can launch on Supabase alone and add Stripe later.
  • BLOB_READ_WRITE_TOKEN — optional. When it is unset, product image uploads fall back to Supabase Storage. That works fine; Vercel Blob is simply faster to serve.
  • Resend — without it, order and account emails are not sent. Everything else still works.
  • SUPABASE_DB_URL is only read by the db:setup and migrate scripts, never by the running site — but set it anyway so future migrations are one command away.

The full list of every supported variable is in Configuration.

3. Click Deploy

  1. Click Deploy
  2. Wait 2–5 minutes for the build to finish
  3. When done, you'll see a link like your-project.vercel.app
  4. Click it — your store is live!

4. Schedule the Cleanup Cron

Your store ships with a maintenance route at /api/cron/cleanup-abandoned-orders. It cancels unpaid cash-on-delivery and bank-transfer orders that were never completed and puts their stock back on the shelf. Nothing calls it on its own — the product does not ship a vercel.json, so you add one.

  1. Create a file called vercel.json in the root of your repository
  2. Paste this in:
{
  "crons": [{ "path": "/api/cron/cleanup-abandoned-orders", "schedule": "0 * * * *" }]
}

0 * * * * runs it once an hour, on the hour. Commit and push the file — Vercel picks up the schedule on the next deployment.

You do not have to wire up the authentication yourself. The route requires an Authorization: Bearer $CRON_SECRET header, and Vercel Cron sends exactly that header automatically as long as CRON_SECRET is set as an environment variable on the project.

Hosting somewhere other than Vercel? Any scheduler works — point it at the same URL and have it send the same Authorization: Bearer header with your secret.

5. Add Your Domain (Optional)

If you have a custom domain (e.g. yourstore.com):

  1. In Vercel, go to your project → Settings → Domains
  2. Click Add Existing, type your domain in the search field, select Connect to an environment → Production, then click Save
  3. Vercel will show you DNS records to add at your domain provider:
    TypeNameValue
    A@76.76.21.21
    CNAMEwwwcname.vercel-dns.com
  4. Wait 5–30 minutes for the domain to connect

6. Update Your URLs

Your store's address changed, so three places need to hear about it:

  1. Vercel: Settings → Environment Variables → change NEXT_PUBLIC_SITE_URL to your domain, including the https:// and with no trailing slash
  2. Supabase: Authentication → URL Configuration → set Site URL to your domain, so password-reset and confirmation links point at the right place
  3. Stripe: if you already configured payments, update your webhook endpoint URL to your domain. Setting it up for the first time? That's Step 3, and you'll use this domain there.
  4. Redeploy: in Vercel, go to Deployments → click the three dots on the latest → Redeploy. Environment variable changes only take effect on a new deployment.

7. Verify the Deployment

The product includes a health check that tells you whether production is actually wired up correctly. Run it from a local clone whose .env.local holds the same values you just entered in Vercel:

npm run post-deploy

It checks that the critical environment variables are set, that Supabase is reachable and has its schema, that the storage bucket exists, and — the one people miss — whether your Stripe keys are still test-mode keys on a live site.

Running your store without Stripe? post-deploy will report the Stripe variables as missing. That is expected — cash on delivery and bank transfer are unaffected.

No local clone? Skip it, and rely on the test purchase in Step 4 instead. Setting up a local clone is covered in Local Development.

Checklist

  • Store deployed and accessible
  • CRON_SECRET set and the cleanup cron scheduled in vercel.json
  • Custom domain connected (if applicable)
  • NEXT_PUBLIC_SITE_URL and the Supabase Auth Site URL updated, then redeployed

Was this step clear?