```html

Building a Printful-Integrated T-Shirt Store on Next.js 14: Architecture, Deployment, and Infrastructure Setup

This post documents the complete technical setup of 86dfrom.com, a print-on-demand t-shirt storefront built with Next.js 14, integrated with Printful's API for inventory management, and deployed across AWS infrastructure (S3, CloudFront, Route53) alongside a Vercel production deployment. The project demonstrates a hybrid architecture pattern combining serverless functions with static asset distribution.

What Was Done

  • Scaffolded a Next.js 14 project with five API routes handling product variants, Printful synchronization, Stripe payment processing, and webhook validation
  • Integrated Printful API for dynamic product variant retrieval and inventory sync
  • Built a complete payment flow with Stripe integration, including webhook endpoints for order confirmation
  • Deployed site files to S3 buckets with CloudFront distribution acceleration
  • Configured Route53 DNS records for domain routing and SSL/TLS certificate validation
  • Set up dual-domain architecture (86dfrom.com and 86from.com redirect) with separate CloudFront distributions

Technical Architecture Overview

The project uses a hybrid deployment pattern: the primary application (Next.js API routes, dynamic pages) runs on Vercel, while static assets and marketing pages are distributed via S3 + CloudFront. This separation allows independent scaling of compute-intensive operations (Printful sync, Stripe webhooks) and high-volume static content delivery.

Directory Structure:

/Users/cb/Documents/repos/sites/86dfrom.com/
├── site/                    # Static HTML files for S3 deployment
│   ├── index.html          # Marketing landing page
│   └── success.html        # Order confirmation page
├── gas/                    # Google Apps Script (future integration)
│   ├── Code.gs
│   └── appsscript.json
├── scripts/
│   ├── deploy.sh           # S3 + CloudFront invalidation script
│   └── get-printful-variants.js  # API variant synchronization
└── .env.local              # Environment configuration (not committed)

Printful API Integration

The scripts/get-printful-variants.js script queries the Printful API to retrieve product variant IDs for the Bella+Canvas 3001 black t-shirt. The Printful API token (scoped to the "86Store" within the dangerouscentaur.com account) provides access to fetch variant metadata including sizes, colors, and inventory status.

Key API endpoints used:

  • GET /api/v2/stores/{store_id}/products — Retrieve product catalog
  • GET /api/v2/products/{product_id}/variants — Fetch specific product variants
  • POST /api/v2/orders — Submit orders for printing (called from Vercel API routes)

The variant IDs (4016, 4017, 4018, 4019, 4020) represent the five available sizes for the black Bella+Canvas shirt. These are stored in the Next.js API route at /pages/api/variants.ts, allowing the frontend to render size options dynamically without hardcoding inventory data.

Vercel Deployment Configuration

The Next.js application is deployed to Vercel production using npx vercel --prod. This deployment handles:

  • API Routes: Five serverless functions in /pages/api/ handle Printful sync, variant retrieval, Stripe payment processing, webhook validation, and order creation
  • Environment Variables: Managed through Vercel's dashboard (Settings → Environment Variables), including PRINTFUL_API_KEY, STRIPE_SECRET_KEY, and STRIPE_WEBHOOK_SECRET
  • Build Process: Next.js 14 builds to optimized static/dynamic pages, verified via npm run build producing a clean compile with no errors across all five routes

The Vercel URL (assigned automatically, e.g., 86dfrom-vercel.app) serves as the origin for dynamic content until DNS cutover.

S3 + CloudFront Infrastructure

Primary Domain (86dfrom.com):

  • S3 Bucket: 86dfrom-com — stores static HTML files (index.html, success.html) and any bundled assets
  • CloudFront Distribution: Accelerates content delivery globally with edge caching and automatic GZIP compression. Origin points to the S3 bucket static website endpoint
  • SSL Certificate: ACM certificate for 86dfrom.com, validated via DNS CNAME records added to Route53
  • Route53 Record: A alias record pointing 86dfrom.com to the CloudFront distribution DNS name

Redirect Domain (86from.com):

  • S3 Bucket: 86from-com configured for website redirect (HTTP 301 to https://86dfrom.com)
  • CloudFront Distribution: Wraps the S3 redirect endpoint for global edge availability
  • CloudFront Function: Custom JavaScript function at the edge intercepts requests and issues permanent redirects, ensuring typo domains reach the canonical URL
  • Route53 Record: A alias record for 86from.com points to the redirect CloudFront distribution

Deployment Script (scripts/deploy.sh):

#!/bin/bash
# Syncs site/ directory to S3 bucket
aws s3 sync ~/Documents/repos/sites/86dfrom.com/site s3://86dfrom-com/ --delete

# Invalidates CloudFront cache to force edge refresh
aws cloudfront create-invalidation \
  --distribution-id E1ABCD1234EFGH \
  --paths "/*"

This pattern (deploy to S3, immediately invalidate CloudFront) ensures cache hits don't serve stale content after updates. The --delete flag removes any files from S3 that are no longer in the local site/ directory.

Key Technical Decisions

Why Hybrid Deployment? Vercel excels at serverless API logic and dynamic rendering, while S3 + CloudFront is cost-effective and performant for static assets. Separating concerns reduces blast radius: asset updates don't trigger function re-deployments, and API logic changes don't invalidate static caches.

Why CloudFront Functions for Redirect Domain? Lambda@Edge (the alternative) adds latency and complexity. CloudFront Functions execute at the edge with microsecond latency, making them ideal for simple request transformation like permanent redirects. The function is deployed via the AWS Console and published to the distribution, avoiding additional Lambda management overhead.

Why ACM Certificates? AWS Certificate Manager certificates are free, auto-renewing, and managed entirely within AWS. No external PKI vendor or manual renewal—Route