npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gregorygrant/nextjs-adapter

v0.1.5

Published

Next.js Adapter for Pantheon.

Readme

Pantheon Next.js Build Adapter

Makes a standard Next.js app build and run on Pantheon, with no changes to the app's repo.

No next.config edit. No dependency to install. No plugin to register. The build environment loads the adapter automatically, and Next.js 16.2's official adapter API does the rest.


Why it exists

The adapter's job is to take whatever Next.js produced and make it behave correctly behind Pantheon's proxy, cache, and CDN, then describe the result in a manifest the deploy pipeline can act on.


What it actually does

Three steps, in order around next build:

1. Tune the build (modifyConfig)

Runs in-build, production only; next dev and next start are untouched. It sets:

| Setting | Why | |---|---| | output: 'standalone' | The app runs as a self-contained Node server behind Pantheon's proxy. | | Pantheon cache handlers | ISR, route, fetch, and 'use cache' all share one object-storage-backed cache. In-memory caching is turned off so the shared cache is the single source of truth. Skipped entirely if the app sets its own cacheHandler. A deliberate choice is never overridden. | | Deterministic build ID | Stable /_next/data/<id>/ URLs across rebuilds of unchanged source. | | Deployment ID | Turns on Next's skew protection, so a visitor on a stale deployment reloads instead of fetching mismatched data. | | trustHostHeader | So request.nextUrl.origin and absolute self-URLs resolve to the real public hostname, not the container's bind address. Next only turns this on for Vercel by default. | | Image-decode concurrency | Next's default misreads CPU count inside a CPU-limited container. Pinned instead to the tenant's real budget. |

Notably absent: any default Server Actions origin allowlist. A platform-wide wildcard entry would make every other tenant's site a trusted origin for this one; host/origin agreement is kept at the HTTP boundary instead, per request. Full reasoning: src/server-actions.ts.

2. Write the manifest (onBuildComplete)

Reads Next's typed build output and writes manifest.json: the canonical description of routes, middleware, and caching hints that the deploy layer consumes. The adapter stays stateless; the builder uploads the file.

3. Stage the output (pantheon-stage)

Runs after next build returns, because Next only writes the standalone/ directory once the hooks are done. It copies .next/static and public/ into the standalone tree, then patches one line of Next's own server.js.

The standalone template hardcodes process.env.HOSTNAME || '0.0.0.0', and a truthy hostname overrides trustHostHeader when Next builds URLs, making that flag dead code for every standalone deploy. Dropping the fallback fixes it, and binding behavior is unchanged.

Build order: next build (adapter injected) → pantheon-stage → package the image.


Usage

The adapter is loaded through the NEXT_ADAPTER_PATH environment variable, with no config change in the app:

pnpm build
export NEXT_ADAPTER_PATH="$(pwd)/dist/index.js"
next build       # Next.js loads the adapter; no config change needed
pantheon-stage   # stage assets, patch server.js

Requirements

  • Node.js >= 22 (developed on 26). Tests run TypeScript natively: no tsx, no ts-node.
  • Next.js >= 16.2 (peer dependency, provided by the build environment). Targets the 16.2 build-output contract, with no shims for older majors.
  • pnpm 11. Settings live in pnpm-workspace.yaml.

Commands

| Command | What it does | |---|---| | pnpm install | Install dependencies. | | pnpm build | Compile src/ → dist/. Entry point matches NEXT_ADAPTER_PATH. | | pnpm test | Run all tests. Add pnpm test:one "<name>" for a single one. | | pnpm typecheck / pnpm lint | Type-check / lint (lint:fix to autofix). | | pnpm e2e:smoke | Build a fixture through the real adapter, boot the staged server, probe it. | | pnpm e2e:local | Run the official Next.js adapter deploy suite locally (one group at a time). | | pnpm clean | Remove dist/. |


Certification

The adapter is validated against the official Next.js adapter deploy suite, which drives it through the three-script harness contract:

| Script | Contract | |---|---| | scripts/e2e-deploy.sh | Builds and "deploys" the test app; prints the deployment URL as its only stdout. | | scripts/e2e-cdn-proxy.mjs | Fronts the origin during e2e runs, applying the edge's Cache-Control normalization. | | scripts/e2e-logs.sh | Replays build/server logs, including the BUILD_ID:, DEPLOYMENT_ID: and IMMUTABLE_ASSET_TOKEN: markers. | | scripts/e2e-cleanup.sh | Tears down whatever the deploy script started. |

.github/workflows/test-e2e-deploy.yml runs the suite across 16 parallel groups against a vercel/next.js checkout, then scripts/upload-adapter-test-results.mjs submits the collected Jest results. Submission requires an ADAPTER_TEST_RESULTS_SECRET repository secret; without it the upload step is skipped.

The deployment URL the harness receives points at a small reverse proxy, not the Node origin directly. A real deploy platform rewrites Cache-Control on prerendered/ISR responses from the origin's s-maxage=... to the browser-facing public, max-age=0, must-revalidate; this origin-only harness has no edge, so the proxy applies that same normalization. Immutable /_next/static assets pass through untouched. Without it the suite's deploy-mode caching assertions would fail against a correctly behaving origin.

The suite runs with no test exclusions. e2e/deploy-tests-overrides.json (the overlay merged onto Next's own manifest via NEXT_EXTERNAL_TESTS_FILTERS) is present but empty. Every case in the deploy suite runs.

Where the suite depends on something the bare origin cannot provide, that thing is supplied rather than excluded around: the CDN proxy above gives the cache-control cases the edge layer they assert against, and the deploy script retries with next build --webpack when an upstream Turbopack defect breaks a build. The overlay file records the bar for adding an entry: an upstream defect reproducible on a plain next build, or a deploy-platform layer the harness genuinely does not include. An adapter bug is never hidden there.


Environment variables

Build time

| Variable | Purpose | |---|---| | NEXT_ADAPTER_PATH | Path to the built adapter. This is the zero-touch load mechanism. | | PANTHEON_BUILD_ID | Pin a deterministic build ID. Unset → Next's default. | | PANTHEON_DEPLOYMENT_ID | Enable skew protection. Unique per deployment, not per build. Unset → off. | | PANTHEON_ALLOWED_ORIGINS | Extra Server Actions origins. Normally unnecessary. | | IMAGE_OPT_CONCURRENCY | Image-decode concurrency; set to the tenant's real vCPU budget. Default 2. | | PANTHEON_DIST_DIR, PANTHEON_ADAPTER_MANIFEST_PATH | Override dist dir / manifest location. |

Runtime

| Variable | Purpose | |---|---| | CACHE_BUCKET | Selects the shared object-storage cache. Without it, caching falls back to files. |


Layout

src/
  index.ts          the adapter itself: modifyConfig + onBuildComplete
  manifest.ts       build the manifest from Next's typed output
  emit.ts           write manifest.json
  stage.ts          copy static/public into standalone, patch server.js
  stage-cli.ts      the `pantheon-stage` command
  env.ts            the one place process.env is read
  build-id.ts, deployment-id.ts, server-actions.ts,
  trust-host-header.ts, image-opt.ts    one config concern each
  cache/            cache-handler injection + handler entry files
test/               unit tests (node:test, native TypeScript)
e2e/                deploy-suite overrides + the smoke-test fixture
scripts/            the deploy-suite harness contract + local runner

License

MIT.