Building a Printful + Stripe Ecommerce Site on Vercel: Infrastructure, Deployment, and API Integration for 86dfrom.com

This post covers the full-stack deployment of a Next.js 14 t-shirt storefront that integrates Printful's print-on-demand API with Stripe payments, hosted on Vercel with CloudFront CDN and Route53 DNS routing. We'll walk through the architecture decisions, credential management, and multi-environment deployment strategy.

Project Structure and Architecture

The 86dfrom.com project follows a modular structure optimized for Next.js 14 and serverless deployment:

  • /site — Static HTML assets (index.html, success.html) and client-side code
  • /gas — Google Apps Script code (Code.gs) for secondary integrations; includes appsscript.json manifest and .clasp.json for Google Apps Script CLI deployment
  • /scripts — Build and deployment automation (deploy.sh for S3/CloudFront invalidation)
  • .env.local — Local development secrets; mirrors production env vars in Vercel dashboard

The Next.js application compiles cleanly to all five API routes and front-end pages. The build process produces no warnings or errors, validated via npm run build.

Credential Management Strategy

This project required integration with three external APIs: Printful (print fulfillment), Stripe (payments), and Google Apps Script (secondary workflows). Each required a different credential handling approach:

  • Printful API Token — Scoped to the "86Store" within the dangerouscentaur.com Printful account. Stored in .env.local as NEXT_PUBLIC_PRINTFUL_API_KEY. Token is account-scoped with all permissions across all stores, issued with expiration set to 2028.
  • Stripe Keys — Two keys required: publishable key (safe to expose client-side) and secret key (server-only). Test keys (sk_test_...) used for staging; live keys (sk_live_...) for production. The secret key never appears in client code or git; stored only in Vercel environment variables and accessed server-side in API routes.
  • Stripe Webhook Secret — Generated after deploying to Vercel (we know the production URL by then). Used in /api/webhook to verify request signatures from Stripe's servers.

All secrets are managed via Vercel's environment variable dashboard, with separate configurations for preview and production branches.

Printful API Integration

The Printful integration populates product variant IDs, which are baked into the frontend during build time. The script /scripts/get-printful-variants.js fetches all variants for the Bella+Canvas 3001 t-shirt (the core product) from the Printful API using the token, filtering for the Plain Black colorway variants (IDs 4016–4020).

These variant IDs are used in form submissions to create orders. The script output is parsed and injected into .env.local as NEXT_PUBLIC_VARIANT_IDS. This approach avoids runtime API calls on the frontend and keeps variant data static throughout the user session.

Infrastructure: Vercel, CloudFront, Route53, and S3

The deployment topology spans multiple AWS regions and services:

  • Vercel — Hosts the Next.js application. Default Vercel domains are available immediately; custom domain DNS is configured after deployment.
  • AWS Route53 — Manages DNS for 86dfrom.com and 86from.com (typo redirect domain). Two hosted zones were created:
    • Zone for 86dfrom.com (primary domain)
    • Zone for 86from.com (redirect to primary)
  • AWS CloudFront — Two distributions deployed:
    • Primary distribution for 86dfrom.com, with S3 origin for static assets and Vercel origin for dynamic content. Configured with HTTP/2 and gzip compression.
    • Redirect distribution for 86from.com, using a CloudFront Function to rewrite all traffic to the primary domain (https://86dfrom.com).
  • AWS S3 — Bucket created for 86dfrom.com static files, with public-read policy scoped to CloudFront OAI (Origin Access Identity). Bucket versioning enabled for easy rollback.
  • AWS ACM — SSL/TLS certificates issued for both domains via DNS validation. Validation CNAMEs added to Route53 automatically.

The CloudFront distributions cache responses aggressively, with cache-control headers set per origin. Static assets in S3 are versioned; dynamic content from Vercel is cached per the application's response headers.

CloudFront Function for Domain Redirect

A CloudFront Function was deployed to handle the 86from.com → 86dfrom.com redirect. The function (published via the AWS CloudFront API) inspects the Host header and performs a 301 permanent redirect if the request comes from 86from.com:

function handler(event) {
  var request = event.request;
  var headers = request.headers;
  var host = headers.host.value;
  
  if (host === '86from.com' || host === 'www.86from.com') {
    return {
      statusCode: 301,
      statusDescription: 'Moved Permanently',
      headers: { 'location': { value: 'https://86dfrom.com' + request.uri } }
    };
  }
  return request;
}

This ensures that users landing on the typo domain are transparently redirected to the canonical 86dfrom.com, preserving URI paths and query strings.

Deployment Workflow

Local Development:

  • Create .env.local with Printful token, Stripe test keys, and variant IDs.
  • Run npm run dev to start the local dev server on localhost:3000.
  • Test checkout flow against Stripe test mode.

Vercel Production Deployment:

npx vercel@latest --prod

This command:

  • Builds the Next.js app using the default Vercel build settings
  • Deploys to Vercel's global edge network
  • Outputs a production URL (e.g., 86dfrom.vercel.app)
  • Integrates with git to enable preview deployments on PR branches

After deployment, environment variables are added to the Vercel dashboard under Settings → Environment Variables, with separate values for Preview and Production. The webhook secret is added after Stripe is configured to send events to https://86dfrom.com/api/webhook.

DNS Configuration

Once Vercel deployment is live, Route53 A records are created to point 86dfrom.com to the Vercel application. The exact DNS values depend on the Vercel deployment; Vercel provides specific CNAME and A records to add to Route53.

The 86from.com (typo domain