Skip to main content

Overview

The Payload pattern deploys a production-ready Payload CMS application to AWS Lambda with:
  • Serverless compute - Lambda functions on ARM64 for cost efficiency
  • Managed PostgreSQL - RDS PostgreSQL (single instance by default, Aurora Serverless v2 optional)
  • S3 storage - media uploads and ISR cache
  • CloudFront CDN - global distribution with HTTPS
  • Automatic patching - Fjall configures the project for Lambda deployment
Payload CMS 3.x is built on Next.js, so it deploys to Lambda via OpenNext.

Quick Start

1. Create a Payload Project

Start with the official Payload website template:

2. Initialise Fjall

This creates the fjall/app/ directory with your infrastructure configuration.

3. Deploy

Fjall patches the project for Lambda, builds it, and provisions the infrastructure.

Scaffolding Payload

Payload CMS offers several official templates. Choose based on your needs: Full-featured website with pages, posts, and media:
Includes:
  • Pages collection with dynamic routing
  • Posts collection with categories
  • Media collection
  • Header/Footer globals
  • Draft/publish workflow
  • SEO fields

Blank Template

Minimal starting point:
Includes:
  • Users collection only
  • No pre-built collections
  • Clean slate for custom schemas

E-commerce Template

Full e-commerce setup:
Includes:
  • Products, Categories, Orders
  • Cart functionality
  • Stripe integration ready

Interactive Setup

Or let Payload guide you:
You’ll be prompted for:
  • Project name
  • Template selection
  • Database type (choose PostgreSQL for Fjall)
  • Package manager
Choose PostgreSQL as your database when scaffolding. Fjall provisions RDS PostgreSQL for the Payload pattern.

Creating Your Fjall App

Basic Setup

After scaffolding Payload, initialise Fjall:
payload and staticsite are the deployable patterns.
The nextjs pattern is not yet deployable — it has no infrastructure construct. Recent CLI versions no longer offer it in the picker and refuse --pattern nextjs at create time; older versions accepted it and failed at first deploy. For a Next.js-based app, use payload; for a static Next.js export, use staticsite.
Running fjall create app interactively asks Choose your configuration tier? with six options: Standard, Lightweight, Resilient, Enterprise, Tinkerer, and Custom. The Custom tier opens a sub-flow for database type, backup retention, deletion protection, KMS encryption, and Lambda memory/timeout. This creates:

Generated Infrastructure

The default infrastructure.ts:
This provisions all resources needed for production deployment.

What’s Included

The Payload pattern provisions:

Automatic Configuration

When you run fjall deploy, the CLI automatically patches your Payload project:

Database Adapter

Replaces your database adapter with @fjall/payload:

S3 Storage

Adds the S3 storage plugin for media uploads:

Next.js Configuration

Configures Next.js for Lambda:
  • output: 'standalone' for OpenNext
  • File tracing for Sharp (ARM64 binaries)
  • Exclusions for unnecessary files

Build-Time Fixes

Patches page files to prevent database calls during build:
All patches are idempotent. Running fjall deploy multiple times is safe.

Deployment Process

First Deploy

The first deployment:
  1. Installs @fjall/payload and @payloadcms/storage-s3
  2. Patches configuration files
  3. Generates OpenNext config
  4. Builds with next build
  5. Deploys infrastructure (~10-15 minutes)

Subsequent Deploys

Updates are faster as infrastructure exists. Only changed resources update.

Post-Deployment

Access Your Site

After deployment, you’ll see:
  • Frontend: https://d1234567890.cloudfront.net
  • Admin Panel: https://d1234567890.cloudfront.net/admin

Create First Admin User

  1. Navigate to /admin
  2. The first-run screen prompts you to create the initial user
  3. Enter an email and password
  4. Sign in to the admin panel

Verify Everything Works

  • Admin panel loads at /admin
  • Can create first admin user
  • Can upload media (stored in S3)
  • Can create/publish content
  • Frontend displays published content
  • Images load correctly

Database Migrations

Payload uses migrations to manage database schema changes.

Generate Migrations

When you change your collections:
This creates migration files in src/migrations/.

Deploy Migrations

Migrations run automatically on Lambda cold start via prodMigrations:
Always generate and commit migrations before deploying schema changes.

Environment Variables

Fjall automatically configures these Lambda environment variables:

Database

OpenNext Cache

Media Storage


Custom Domain

To use a custom domain:
Or with manual certificate configuration:
The certificate must be in us-east-1 for CloudFront.

Pattern Parameters

The Payload pattern accepts configuration options for each component:

Full Configuration Example

Root Options

Database Options

See the DatabaseFactory documentation for the full list of available database parameters.

CDN Options

Compute Options

Messaging Options


Breaking Out Components

Need more control? You can break out of the pattern and use individual factories.

Why Break Out?

  • Add additional resources (Redis, queues, etc.)
  • Customise networking (VPC peering, private subnets)
  • Share resources between multiple apps
  • Fine-grained IAM permissions

From Pattern to Factories

The Payload pattern can be approximated with this factory composition:
This example demonstrates factory composition concepts. The actual Payload pattern includes additional configuration like environment variables, IAM policies, and CDN behaviours that are automatically configured for optimal OpenNext deployment.

Adding Extra Resources

Once broken out, easily add more resources:

Sharing Resources Between Apps

Create shared infrastructure:
Reference from your Payload app:

Troubleshooting

Build Fails: “Error occurred prerendering page”

Cause: Page tries to access database at build time. Fix: The Fjall CLI handles this automatically. Update to the latest version:

403 on Admin Panel Actions

Cause: CSRF configuration issue. Fix: Set csrf: [] explicitly in payload.config.ts:

Media Uploads Disappear

Cause: Using local filesystem instead of S3. Fix: Fjall automatically configures S3 storage. If you have customised plugins/index.ts, keep the S3 plugin in the list.

”relation does not exist”

Cause: Migrations not generated or prodMigrations not configured. Fix:

Costs

Estimated monthly costs for a low-traffic site:
Set database.type: "Aurora" to use Aurora Serverless v2, which scales to zero when idle and can lower the database cost for bursty or low-traffic sites.

Next Steps

Add Resources

Extend your app with additional AWS services

Compute Factory

Learn about Lambda and ECS options

Storage Factory

Configure databases and S3 buckets

CI/CD

Automate deployments with Buildkite

Fjall: External: