Building a Printful-Integrated T-Shirt E-Commerce Site: Next.js 14, Vercel, and AWS Multi-Domain Setup
This post documents the complete build and deployment of 86dfrom.com, a Printful-integrated t-shirt storefront. We cover the full stack: Next.js 14 API routes for Printful variant fetching, Stripe payment integration, multi-domain DNS routing across Route53, and CloudFront distribution setup for both primary and redirect domains.
What Was Done
- Built a Next.js 14 full-stack application with clean, production-ready routing
- Integrated Printful API for real-time product variant management
- Configured Stripe payment processing with webhook support
- Deployed dual-domain infrastructure:
86dfrom.com(primary) and86from.com(redirect) - Set up AWS S3, CloudFront, Route53, and ACM certificate validation across two domains
- Established Google Apps Script backend for order fulfillment workflows
Architecture Overview
The system uses a three-tier architecture:
- Frontend: Next.js 14 deployed to Vercel (primary site)
- Static Assets: S3 buckets with CloudFront distributions for fast global delivery
- Payment Processing: Stripe API with webhook handlers at
/api/webhook - Print Fulfillment: Printful API integration + Google Apps Script automation
- DNS/Routing: Route53 hosted zones managing both
86dfrom.comand86from.comwith domain consolidation via CloudFront
Technical Details: Project Structure
The project is organized across multiple directories:
/Users/cb/Documents/repos/sites/86dfrom.com/
├── site/ # Static HTML (pre-rendered or backup)
│ ├── index.html # Main storefront
│ └── success.html # Order confirmation page
├── gas/ # Google Apps Script
│ ├── Code.gs # Fulfillment automation
│ └── appsscript.json # GAS manifest with scopes
└── scripts/
└── deploy.sh # Automated S3 + CloudFront deploy
The Next.js application at /Users/cb/Desktop/86dfrom (monorepo structure) contains:
pages/api/variants.js— Fetches Printful variant IDs for Bella+Canvas 3001 Black (SKU variants 4016–4020)pages/api/webhook— Stripe webhook endpoint for payment confirmations.env.local— Environment variables (Printful API key, Stripe secret, webhook secret)public/fonts/Anton.woff2— Preloaded Google Font (self-hosted to avoid external dependency)
Printful API Integration: Variant Fetching
The scripts/get-printful-variants.js script queries the Printful API to retrieve product variant IDs:
node scripts/get-printful-variants.js
Why this approach: Variant IDs are stable but must be fetched once per product configuration. Hardcoding them would break if the product changes; fetching them at build time keeps .env.local minimal and allows runtime updates.
For 86dfrom.com, we target the Bella+Canvas 3001 unisex t-shirt in Black. The API returns variant objects; we extract the five size variants (4016–4020) representing XS through XL.
Infrastructure: AWS Multi-Domain Setup
S3 Buckets:
86dfrom.com— Primary static site bucket86from.com— Redirect bucket (lower traffic, domain consolidation)
ACM Certificates:
- Requested separate certificates for both
86dfrom.comand86from.com - DNS validation via Route53 CNAME records (fully automated, no manual email confirmation required)
- Certificate status polled until
ISSUEDbefore creating distributions
CloudFront Distributions:
- Primary Distribution (86dfrom.com):
- Origin: S3 bucket
86dfrom.com - Default root object:
index.html - Viewer protocol policy: Redirect HTTP to HTTPS
- Cache behavior: TTL 3600s for HTML, 31536000s for versioned assets
- Alternate domain names:
www.86dfrom.com
- Origin: S3 bucket
- Redirect Distribution (86from.com):
- Origin: S3 bucket (redirect bucket)
- Function: CloudFront Function at
us-east-1rewrites all requests to HTTPS redirect to primary domain - Prevents duplicate content; consolidates traffic to primary domain
Route53 Configuration:
# Primary domain
86dfrom.com A [CloudFront dist alias]
www.86dfrom.com A [CloudFront dist alias]
# Redirect domain
86from.com A [CloudFront redirect dist alias]
Alias records point to CloudFront distributions (no additional costs, auto-health-checked).
Deployment Strategy
Static Assets (S3 + CloudFront):
The scripts/deploy.sh script handles automated deployment:
#!/bin/bash
aws s3 sync site/ s3://86dfrom.com --delete
aws cloudfront create-invalidation --distribution-id [DIST_ID] --paths "/*"
This ensures:
- Files deleted locally are removed from S3 (no stale assets)
- CloudFront cache is invalidated immediately (no wait for TTL expiration)
- Global CDN refresh within seconds
Next.js Application (Vercel):
The primary application deploys to Vercel:
npx vercel@latest --prod
Why Vercel: Zero-config Next.js deployment, automatic HTTPS, environment variable management, and webhook endpoint accessibility (critical for Stripe).
Environment Variables in Vercel:
PRINTFUL_API