All Blog Articles

Payload NextJS: Configuring Environment Variables and Webpack for Your Project

Media
Sandro WegmannMarch 6, 2025
Basic Setup for Payload NextJS: Adjusting Configuration

In this third part of our Payload NextJS tutorial series, we will dive into the essential configurations needed for your project. We'll explore how to set up environment variables dynamically, adjust your Webpack configuration, and ensure smooth authentication between your front end and back end.
This is the written guide for our Comprehensive Payload NextJS Setup Guide Series (Part 3). You can find the full length video here:
https://www.youtube.com/watch?v=lmeOiOtvdT8

Table of Contents


Introduction to Environment Variables

Environment variables are essential for configuring your application without hardcoding values directly into your code. They allow you to manage settings like API keys, database URLs, and server ports. In a Payload NextJS project, these variables can make your application more flexible and easier to manage across different environments such as development, testing, and production.

In this section, we will focus on how to set up and utilize environment variables effectively, ensuring that your application behaves correctly in various scenarios.

Adding New Environment Variables

To enhance the functionality of your Payload NextJS application, you may need to add new environment variables. Here’s a simple way to do that:

  1. Open your project’s configuration file, typically found at the root of your project.
  2. Add the following environment variables:
    • payload_public_external_server_url: This will define the external server URL.
    • port: This will specify the dynamic port your application will run on.
    • payload_env: This will indicate the current environment (development, testing, or production).
  3. Set the values for these variables appropriately. For example, you might set payload_public_external_server_url to http://localhost:4000.

Understanding Payload Public External Server URL

The payload_public_external_server_url variable is crucial as it replaces the hardcoded server URL in your configuration. This allows the Payload admin panel to access the correct server URL dynamically.

When using this variable, it’s important to prefix it with payload public. This is similar to how environment variables are treated in Next.js, where front-end accessible variables are prefixed with next public. This distinction helps maintain security while still providing necessary information to your frontend.

Payload-Public-External-Server-URL.png


Setting Up Dynamic Port Configuration

Static ports can be problematic, especially when deploying your application in different environments. To avoid issues, it’s essential to set up a dynamic port configuration.

In your server.ts file, replace any hardcoded port number with process.env.port. This will allow your application to utilize the port defined in your environment variables, making it adaptable for various deployment scenarios.


Disabling GraphQL

If you’re not utilizing GraphQL in your application, it’s best to disable it entirely. This can be done by modifying the GraphQL attributes in your Payload configuration.

Simply remove all existing settings and add the line:

disable: true

This will ensure that GraphQL is not included in your application, reducing unnecessary overhead.


Managing Collections in Payload

When starting with a new Payload project, you typically have a default collection setup. The primary collection is often users, which is critical for authentication. You can manage this collection by adjusting its settings to fit your needs.

For example, if you want to use this collection with a separate frontend, you’ll need to modify the authentication settings. Specifically, replace the auth: true attribute with a cookie configuration object that specifies secure and same-site settings based on your environment.

  • Secure: Set to process.env.payload_env !== 'development'.
  • Same Site: Adjust based on your environment, using process.env.payload_env === 'testing' for a value of none.

This configuration ensures that your application can handle cookies correctly, enhancing security while maintaining functionality across different environments.

Managing-Collections-in-Payload.png


Implementing Whitelist Origins for CORS

To enable cross-origin requests from your frontend, you’ll need to implement a whitelist for origins. This is particularly important when your frontend and backend are served from different domains.

In your Payload configuration, add the following:

cors: process.env.whitelist_origins.split(',')

This will allow you to specify multiple origins, enhancing security while still enabling necessary API calls from your frontend.


Configuring Cookies for Frontend Authentication

Setting up cookies correctly is crucial, especially when dealing with authentication across different environments. To ensure that your Payload NextJS application can handle cookies securely, we need to adjust the authentication settings of your main collection.

Instead of using a simple auth: true attribute, we will replace it with a cookie configuration object. This allows for more granular control over cookie behavior:

cookies: {
    secure: process.env.payload_env !== 'development',
    sameSite: process.env.payload_env === 'testing' ? 'none' : 'lax'
}

The secure setting ensures that cookies are only transmitted over HTTPS, which is necessary in production but can be disabled during development on localhost. The sameSite attribute helps mitigate CSRF attacks by controlling how cookies are sent with cross-origin requests.

Cookies-for-Frontend-Authentication.png


Dynamic settings based on the environment are essential for maintaining a secure and functional application. In development, we often work under less secure conditions (e.g., HTTP), so disabling secure cookies allows for smoother testing. Conversely, in production, we enforce secure cookies to protect user data.

By using the payload_env variable, we can easily switch between these configurations without needing to change the code directly.

Implementing Whitelist Origins for CORS

Cross-Origin Resource Sharing (CORS) is a critical aspect of web security that allows or restricts resources on a web page to be requested from another domain. In a typical setup with Payload NextJS, you will need to specify which origins are permitted to interact with your backend.

To set this up, you will add an environment variable called whitelist_origins to your configuration. This will contain a comma-separated list of origins that your backend should allow:

cors: process.env.whitelist_origins ? process.env.whitelist_origins.split(',') : []

This configuration ensures that if no origins are specified, an empty array is returned, preventing any unwanted access.

Whitelist-Origins-for-CORS.png


Handling CSRF Protection

In addition to the CORS settings, you should also configure CSRF protection to safeguard against cross-site request forgery attacks. This is done similarly by specifying the same origins for CSRF requests:

csrf: process.env.whitelist_origins ? process.env.whitelist_origins.split(',') : []

By aligning your CORS and CSRF settings, you ensure a consistent security posture for your application.

Adjusting Package JSON for Deployment

To streamline the deployment process, particularly on platforms like Railway, it's important to make a couple of adjustments to your package.json file. First, replace the npm run serve command with npm run start. This change simplifies the deployment process as Railway automatically runs npm run build followed by npm run start.

Next, extend the copy_files script to include additional file types that might be necessary for your build:

copy_files: {
    ejs: 'src/**/*.ejs',
    json: 'src/**/*.json',
    // Add other file types as needed
}

This ensures that all necessary files are included in the build, preventing potential runtime errors due to missing assets.


Configuring Webpack to Handle Server-Only Modules

When working with server-only modules like the fs module, it's critical to configure Webpack to prevent these from being included in the client-side bundle. This can be achieved by creating a mock for the module that simply exports an empty function.

First, create a new folder called mocks in your source directory, and add a file named emptyFunction.js:

export default function() {}

Next, in your Payload configuration under the admin attribute, import this mock and configure Webpack:

webpack: (config) => {
    config.resolve.alias['fs'] = path.resolve(__dirname, 'mocks', 'emptyFunction.js');
    return config;
}

This setup effectively tells Webpack to ignore the fs module during the bundling process, preventing errors when your application runs in the browser.


Conclusion and Next Steps

In this tutorial, we've covered essential configurations for your Payload NextJS project, including cookie management for authentication, CORS settings, package adjustments for deployment, and Webpack configurations for server-only modules. By implementing these practices, you can ensure a more secure and efficient application.

As you proceed, consider exploring additional features such as file uploads using an S3 bucket and user management through the Payload admin panel. These enhancements will further strengthen your application’s capabilities.


FAQ

What is the purpose of the payload_env variable?

The payload_env variable helps distinguish between different environments (development, testing, production) and allows for dynamic configuration of settings like cookies and CORS.

How do I handle authentication from a separate frontend?

Ensure that your cookie settings allow for cross-origin requests and that you have whitelisted the frontend origins in your CORS configuration.

Why is it necessary to mock server-only modules in Webpack?

Server-only modules like fs cannot be executed in a browser environment. Mocking them prevents Webpack from including them in the client-side bundle, avoiding runtime errors.

Can I use TypeScript in my Payload project?

Yes, you can use TypeScript for your Payload project. However, ensure that your main configuration files remain in TypeScript to leverage type safety.