Next.js SSR
Copy it into a new project:
pnpm dlx degit antstanley/blogwright/examples/nextjs-ssr my-siteNext.js with output: 'standalone', running on a Lambda Web Function. Next serves its own assets, so nothing publishes to S3.
| Framework | Mode | Blogwright config | Source |
|---|---|---|---|
| Next.js standalone | Server-rendered | ssr |
examples/nextjs-ssr |
Deploy it
Section titled “Deploy it”-
Copy the example and start a repository:
Terminal window pnpm dlx degit antstanley/blogwright/examples/nextjs-ssr my-sitecd my-site && git init -
Set
siteNameandregioninconfig/production.jsonc. For SSR,regionmust beus-east-1,us-east-2,us-west-2,ap-northeast-1oreu-west-1. -
Add Blogwright, then commit everything, including
pnpm-lock.yaml- the builder installs with--frozen-lockfile:Terminal window pnpm add -D blogwrightgit add -A && git commit -m "Start from the blogwright example" -
Create the infrastructure:
pnpm exec blogwright bootstrap -
Build and publish:
pnpm exec blogwright deploy
What matters
Section titled “What matters”pnpm-workspace.yaml-nodeLinker: hoisted. Next copies tracednode_modulesentries into.next/standaloneas it finds them, so pnpm’s default symlink tree would come through as symbolic links, which the build agent rejects.next.config.js-output: 'standalone', andoutputFileTracingRootpinned to this directory. Without it Next infers the root from the nearest lockfile above the project, and inside a larger repository nests the server at.next/standalone/<path>/server.js.package.json- the build copiespublic/and.next/static/into the standalone package (Next leaves them out), plus the shim. Next serves/_next/static/asimmutable, so CloudFront caches it like any other cacheable response.lambda.mjs- the entry shim. It mapsAWS_LAMBDA_HTTP_ENDPOINTontoHOSTNAMEandPORT, then importsserver.js.config/production.jsonc- packages.next/standalone, with nostaticDir. If the app uses Server Actions, add your domain toserverActions.allowedOrigins: the app receives the endpoint’s domain asHost.
The files
Section titled “The files”// Blogwright config for this example. Paths are relative to the repository// root, so they assume this directory IS the repository - see README.md.{ "region": "us-east-1", "siteName": "nextjs-ssr", "ssr": { // Next serves public/ and /_next/static/ itself (the build copies them into // the package), so there is no staticDir. "packageDir": ".next/standalone", "entryPoint": "lambda.mjs", },}/** @type {import('next').NextConfig} */export default { // A self-contained server in .next/standalone, with the node_modules files it // traced copied in. output: 'standalone', // Trace from this directory, so server.js lands at .next/standalone/server.js // even when the project sits inside a larger repository. outputFileTracingRoot: import.meta.dirname,};// Entry shim for Lambda Web Functions. Lambda passes the listen address in// AWS_LAMBDA_HTTP_ENDPOINT; Next's standalone server reads HOSTNAME and PORT.const endpoint = process.env.AWS_LAMBDA_HTTP_ENDPOINT;const colon = endpoint.lastIndexOf(':');process.env.HOSTNAME = endpoint.slice(0, colon);process.env.PORT = endpoint.slice(colon + 1);await import('./server.js');# A workspace of its own, so pnpm treats this directory as the project root# even inside the blogwright repository.packages: - .
# Real files instead of pnpm's symlink tree: Next copies node_modules into# .next/standalone as it finds them, and Blogwright rejects a package that# contains a symbolic link.nodeLinker: hoisted{ "name": "blogwright-example-nextjs-ssr", "private": true, "type": "module", "packageManager": "pnpm@11.25.0", "scripts": { "dev": "next dev", "build": "next build && cp -R public .next/standalone/ && cp -R .next/static .next/standalone/.next/ && cp lambda.mjs .next/standalone/" }, "dependencies": { "next": "^16.4.0", "react": "^19.3.0", "react-dom": "^19.3.0" }}Check the package locally
Section titled “Check the package locally”Run it the way Lambda does - from a copy outside the project, so nothing resolves from its own node_modules:
pnpm buildcp -R .next/standalone /tmp/pkg && cd /tmp/pkgAWS_LAMBDA_HTTP_ENDPOINT=127.0.0.1:8080 node lambda.mjscurl -i http://127.0.0.1:8080/The server must start listening within 10 seconds, and find .next/standalone -type l must print nothing: the build agent rejects a package that contains a symbolic link.
Related pages
Section titled “Related pages”- Server-rendered sites: Next.js - the full recipe and its options
- Examples overview - every example, and the conventions they share