Next.js Self Hosted Demo

This is a demo of a Next.js application hosted on Ubuntu Linux. It also includes a Postgres database and an Nginx proxy. View the code.

Data Fetching

Random Pokemon: tentacruel

This value was retrieved with fetch from an API. This page is served dynamically, fetching a random Pokemon on each request. Reload to see a new Pokemon.

Image Optimization

Coding

Next.js supports image optimization out of the box with next start. The image above is using the default image optimization on the Next.js server.

In Next.js 15, you no longer need to install sharp manually for image optimization, whether local or remote. You can also use a custom image loader for external optimization services.

You can also bring your own custom image loader, if you would prefer to use a different service. You can view an example here, which you can enable through next.config.ts.

Read the docs

Streaming

The Next.js App router supports streaming responses. This demo usesSuspense with an async component to stream in different components with a delay. We let Nginx handle compression for our application, and then disable proxy buffering to enable streamed responses.

View the demo

Read the docs

Postgres Database

This route reads and writes to our Postgres database, which is in its own Docker container. It uses Drizzle for the ORM. There is also a cron job that resets the demo data every 10 minutes. You can manually hit the endpoint the cron uses by sending a POST to /db/clear

View the demo

Caching / Incremental Static Regeneration

By default, Next.js ISR uses an lru-cache and stores cached entries in memory. This works without configuration, for both caching data as well as ISR, in both the Pages and App Router.

If you prefer to override the cache location, you can store entries in something like Redis. For multi-container applications, this is strongly recommended, but for this single container app it’s not necessary.

For this demo, we have a route that retrieves data with fetch from an API, then adds a time-based revalidate time of 10 seconds. This indicates it will be "fresh" for a maximum of that time. You can view the s-maxage=10, stale-while-revalidate=31536000 response header for the page.

The default stale-while-revalidate time for static pages that do not specify a revalidate time is 1 year, however, this can also be configured with swrDelta in next.config.ts.

View the demo

Read the docs

Middleware

The /protected route is protected by a cookie. You will be redirected back to /. To view the route, add the protected=1 cookie in the browser.

Middleware does not have access to all Node.js APIs. It is designed to run before all routes in your application. However, we are planning to allow support for using the entire Node.js runtime, which can be necessary when using some third-party libraries.

It is not recommended to do checks like fetching user information from your database inside of Middleware. Instead, these checks should happen before queries or mutations. Checking for an auth cookie in Middleware in the preferred pattern.

View the demo

Read the docs

Server Startup

Next.js includes an instrumentation file that runs some code when the server starts.

This instrumentation file will be stabilized in Next.js 15. A common use case is reading secrets from remote locations like Vault or 1Password. You can try this by setting the appropriate variables in your .env file for Vault, though it's not required for the demo.

Read the docs

Environment Variables

Next.js supports loading environment variables from .env files.

When reading values from a Server Component, you can ensure that the env var is read dynamically every time. For container setups, a common use case here is to provide different env vars per environment, with the same Docker image.

This value was read from process.env: maplesmoked

Read the docs