```html

Building a Printful-Integrated T-Shirt Store with Next.js 14, Stripe, and AWS Infrastructure

Overview

This post documents the complete build of 86dfrom.com, a print-on-demand t-shirt storefront using Next.js 14, integrated with Printful for inventory/fulfillment and Stripe for payments. The infrastructure spans Vercel (hosting), AWS S3 + CloudFront (static assets), Route53 (DNS), and Google Apps Script (backend automation).

Project Structure

The application is organized as a monorepo with clear separation of concerns:

  • /site – Static HTML landing page and checkout success confirmation
  • /gas – Google Apps Script backend for form handling and webhook processing
  • /scripts – Deployment and data-fetching utilities
  • .env.local – Environment configuration (Stripe keys, Printful API token)

The Next.js application is built on Next.js 14 with five core routes:

  • /api/variants – Returns available t-shirt variants from Printful
  • /api/checkout – Initiates Stripe Checkout session
  • /api/webhook – Receives Stripe webhook events (payment confirmations)
  • /success – Post-purchase confirmation page
  • / – Home page with product selector and checkout button

Printful Integration

Printful serves as the fulfillment partner, providing:

  • Inventory management: Store configuration and product variants
  • Print-on-demand: No upfront inventory costs; printing/shipping only on order
  • API access: Retrieve variant IDs, pricing, and product metadata

The integration begins with the scripts/get-printful-variants.js script, which:

  1. Authenticates to the Printful API using the store token (scoped to "86Store")
  2. Queries GET /v2/products to retrieve all configured products
  3. Filters for the Bella+Canvas 3001 Black unisex t-shirt (variants 4016–4020, covering XS–2XL)
  4. Outputs variant IDs as JSON to populate .env.local

This decoupling allows the storefront to fetch variant data at deploy time rather than runtime, reducing API calls and improving page load performance. The variant IDs are then baked into environment variables:

NEXT_PUBLIC_PRINTFUL_VARIANT_XS=4016
NEXT_PUBLIC_PRINTFUL_VARIANT_S=4017
NEXT_PUBLIC_PRINTFUL_VARIANT_M=4018
NEXT_PUBLIC_PRINTFUL_VARIANT_L=4019
NEXT_PUBLIC_PRINTFUL_VARIANT_XL=4020

Stripe Payment Processing

Stripe handles the entire payment workflow:

  • Checkout sessions: /api/checkout creates a Stripe Checkout session with line items, customer info, and success/cancel URLs
  • Webhooks: /api/webhook listens for payment_intent.succeeded and charge.completed events to trigger order fulfillment
  • Keys: Publishable key (client-side) for Stripe.js; secret key (server-side) for session creation and webhook validation

The webhook endpoint validates the Stripe signature using the webhook secret, then forwards payment data to the Google Apps Script backend for order processing and inventory tracking.

Infrastructure: Vercel, S3, CloudFront, and Route53

Primary hosting (Vercel):

  • Next.js application deployed to Vercel's serverless platform
  • Routes automatically map to Lambda functions for API endpoints
  • Environment variables configured via Vercel project settings
  • CI/CD triggered on pushes to the primary Git branch

Static assets and CDN (AWS):

  • S3 bucket: 86dfrom-site holds static HTML, CSS, and images
  • CloudFront distribution: Edge locations cache assets globally; accelerates asset delivery
  • ACM certificate: TLS termination for HTTPS on 86dfrom.com
  • Route53 hosted zone: DNS records point 86dfrom.com to CloudFront, and direct to Vercel via ALIAS record

The S3 bucket policy restricts direct access, requiring all traffic to flow through CloudFront. This simplifies cache invalidation and provides a single point of control for content distribution.

DNS and domain routing (Route53):

  • ALIAS record for 86dfrom.com → Vercel's project domain
  • ALIAS record for www.86dfrom.com → CloudFront distribution
  • ACM certificate validation via DNS CNAME records (automated during cert provisioning)

A secondary distribution was created for 86from.com (note the missing 'd') as a redirect; any traffic to that domain is forwarded to 86dfrom.com via a CloudFront Function at the viewer-request stage.

Google Apps Script Backend

The /gas/Code.gs file provides a lightweight backend for:

  • Webhook relay: Receives forwarded payment events from /api/webhook
  • Google Sheets integration: Logs orders to a spreadsheet for manual review and fulfillment tracking
  • Email notifications: Sends confirmation emails to customers and admins

The appsscript.json manifest declares scopes for Sheets and MailApp, allowing the script to read/write order data and send email. This approach keeps sensitive business logic off Vercel and integrates seamlessly with Google Workspace tools.

Deployment Pipeline

Static site deployment (S3 + CloudFront):

The scripts/deploy.sh` script:

  1. Copies static files from /site to the S3 bucket
  2. Sets MIME types and cache headers appropriately
  3. Invalidates the CloudFront distribution cache to ensure fresh content

Next.js deployment (Vercel):

Via npx vercel@latest --prod:

  1. Vercel builds the Next.js application (clean compile verified locally)
  2. API routes are deployed as serverless functions