Issues with displaying public images in Next.js production build are being reported

My Next.js app is deployed on Heroku. Images show up when I develop locally, but once pushed to Heroku and checked on the live site, the images return a 404 error. The images (.png) are stored in a public folder within my project, and I reference them in the code like this:

<Image
    src="/wb_blue_white.png"
    alt="WB Concept"
    width="70"
    height="70"
    className={navStyles.logo}
/>

Despite the image sources being the same

src="/_next/image?url=%2Fwb_blue_white.png&w=256&q=75"
both locally and in production, I am only able to view them when running the project localhost. What could be causing this discrepancy between localhost and the Heroku build?

Here is an excerpt from my package.json file:

"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start -p $PORT"
},

File structure of the project:

components
pages
public

Answer №1

Take a look at the custom server documentation for Next.js and the corresponding example repository.

In the code snippet that resembles Express, the use of app.render() appears to map routes in Next.js from /a to pages/a. It's unclear if this mapping is necessary for each path or merely for demonstration purposes. Feel free to experiment.

If it functions similar to a basic Express server, as I assume, calling the use() method on the express instance will add middleware that 1. processes incoming requests and 2. forwards them to the next middleware or sends a response to the client.

By using

server.use(express.static(path.join(__dirname, 'public')));
, where server represents the express instance (following convention in the example repository), you can include middleware to serve static files.

I can't quite remember the exact process of configuring Express, but it should be either:

  • right after instantiating express(), or
  • right before calling listen()

Simply inserting

server.use(express.static(path.join(__dirname, 'public')))
at one of these points should work.

Answer №2

I encountered a similar issue recently. The problem, as it turned out, wasn't with the components themselves. I was actually hosting my site on Netlify and didn't realize that it automatically builds devDependencies by default. This led to node packages meant for development and testing being compiled for production, causing errors.

To fix this, I adjusted the NODE_ENV setting in Netlify to production and rearranged the packages between dependencies and devDependencies. After making these changes, the error disappeared.

I suspect that the components were triggering the issue because they required initial requests that generated or optimized them server-side. This ultimately caused dev packages to run in the wrong context due to remote image requests.

I share this experience in the hopes that it may assist someone else facing a similar situation in the future.

Answer №3

Ensure that your images are stored in the public folder, for example, public/pictures.

Next, insert the following code snippet into your next.config.js file:

images: {
      {
        protocol: 'http',
        hostname: 'localhost',
        port: '3000',
        pathname: '/pictures/**',
      }, 
      {
        protocol: 'https',
        hostname: '<YOUR WEBSITE URL>.com',
        port: '',
        pathname: '/pictures/**',
      },
    ],
  },

After making these changes, upload your project again and restart all dynos to see the updated images.

Answer №4

To achieve the desired outcome, establish a new folder for images within the main directory and import them from there using relative paths.

Answer №5

If you're wondering about why Sharpe is missing in production, there are numerous articles discussing this topic. Essentially, Sharp must be installed as it is a requirement. The NextJS documentation may make it seem optional, but in reality, with the default loader, Sharp is essential for proper functioning.

Answer №6

After realizing I had included the public folder in my .dockerignore file, I discovered that all of my static assets were being ignored. Hopefully this information can assist someone else facing a similar issue.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Accessing Google Analytics with a single OAuth token using the JavaScript API: A step-by-step guide

I'm currently developing a webpage for exclusive users to view shared Google Analytics data. I have managed to obtain an OAuth token for the account housing this data using JavaScript, but sadly it expires in just 1 hour. Is there a way to utilize th ...

Increasing values in Mongoose using $inc can be done by following these steps

I've been struggling to increment a field value using $inc in my code. My schema looks like this: var postSchema = mongoose.Schema({ title : { type: String, required: true }, body : { type: String, default: '' }, coun ...

"Transferring an array of data to a Laravel controller via AJAX: A step-by-step guide

Is there a way to send arrays of data to the back-end all at once? The Problem 1. This is what I'm currently sending: array:5 [ "_token" => "S5s5ZTTnnP93MyXgCql0l9vhHsiqt5VWaFyEedXj" "product_id" => "21" "specification_id" => "6" " ...

Place a new button at the bottom of the react-bootstrap-typeahead dropdown menu for additional functionality

Currently, I have successfully implemented the React Bootstrap Typeahead with the desired options which is a good start. Now, my next challenge is to integrate a custom button at the end of the dropdown list for performing a specific action that is not ne ...

Tips for avoiding the automatic transition to the next slide in SwiperJS

How can I prevent the next button click in swiper based on my custom logic? I am using the swiperjs library within a Vue project and I need to stop users from swiping or clicking the next button to move to the next slide depending on certain conditions de ...

sending information back to the controller with get method (ajax, javascript)

I'm currently facing a challenge where I have an event listener waiting for a button to be pressed. Once the button is pressed, the controller method 'update' is called which then triggers the view method 'input' to fetch data from ...

Tips for handling useEffect alert while working with Recoil

I've successfully implemented the Recoil docs to create the code below, which is functioning properly. However, I am encountering the following warning: Warning: Can't perform a React state update on a component that hasn't mounted yet. Thi ...

Gather every hyperlink and input fields without utilizing jQuery

Is there a way to target all a and form elements without relying on jQuery? My end goal is to achieve the following functionality: document.querySelectorAll('a').forEach(element => { element.addEventListener('click', () => { ...

Having trouble generating a dynamic ref in Vue.js

I am currently working on rendering a list with a sublist nested within it. My goal is to establish a reference to the inner list using a naming convention such as list-{id}. However, I'm encountering difficulties in achieving this desired outcome. B ...

Managing the invocation of a promise multiple times in AngularJS, and handling some specific exceptions

After previously asking a question on handling promises multiple times in AngularJS (AngularJS handle calling promise multiple times), I am facing a new challenge. This time, I need to retrieve a list of cities, but encounter an exception. Similar to how ...

Directive for integrating Amcharts with Angular JS

I have created a custom directive specifically for displaying a single chart using Amcharts. angular.module("App").directive('myElem', function () { return { restrict: 'E', replace:true, temp ...

Ajax: Why am I receiving an error response instead of a successful one?

It's puzzling why my code is triggering the error function instead of success. The console.log keeps showing me this: Object {readyState: 0, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: f ...

Is it possible to retrieve the vertices array from a QuickHull instance in three.js?

I'm currently working on generating a geometry using QuickHull from a THREE Mesh. However, it seems that the QuickHull object only contains information pertaining to the Faces of the mesh. Does anyone know if there is a way to access the vertex infor ...

Switch the checked status of an input dynamically using jQuery function

It seems like I might be overlooking something quite obvious, but I can't figure out why this jquery function is behaving inconsistently. HTML: <label id="income_this_tax_year"> <div class="left"> <p>Have you had Self-Employm ...

Updating a string in JavaScript by dynamically adding values from a JSON object

In my current function, I am making a request to fetch data and storing it as an object (OBJ). Afterwards, I make another request to get a new URL that requires me to update the URL with values from the stored data. The information saved in the object is ...

Sharing data with child components in Next.js through getStatisticProps

Is it possible to use getStaticProps only in the pages area, or can I also utilize a template from the components? I am looking to pass data from pages/index.js export default function Home({posts}) { return ( <div> <Head> ...

The attribute selector specifically targets the number 3, excluding numbers such as 13 or 23 from being selected

Within a form, there is a segment that displays groups of 4 weeks in each division. Take a look at the code snippet provided below <div class="form-check" data-weeknr="1,2,3,4"></div> <div class="form-check" dat ...

Iterating variables in Vue.js is reminiscent of the process in AngularJS

When working on my application using vue.js, I am interested in finding the last repeated element within a v-for directive. I understand that in angularjs, there is a similar concept using the $last loop variable in its ngRepeat directive: <div ng-repe ...

Catalog of items in Mustache

I am currently working on generating HTML content using the mustache template engine. However, I have encountered an issue when trying to render a list of objects. Below is an example of my object: var Prod={ "Object1": { "name": "name1", "cat ...

The API response indicates that the service is currently not accessible

I'm attempting to retrieve a report from the MOZ API, but I keep receiving this response: { "status" : "503", "error_message" : "Service Temporarily Unavailable" } This is the code I am using: function MozCall(callback) { var mozCall = ' ...