g1st
g1st

Reputation: 45

Why does NextJs requires restart before files added to public are visible

probably a noob question but please do enlighten me.

Let's say I create a clean new project mkdir nextjs_app && cd nextjs_app, then install three packages to start basic nextjs project npm install react react-dom next followed by npm init -y. Then add scripts:

  "dev": "next",
  "build": "next build",
  "start": "next start"

and add empty public folder.

Now if app started in dev mode npm run dev and I add some image.jpg inside public and navigate to http://localhost:3000/image.jpg I can access it just fine.

But if I run npm run build and npm run start, again I add manually image.jpg to public and then try to access it at http://localhost:3000/image.jpg I get a 404 Not Found. I have to stop the app ctrl + c and just start it again npm run start (no need to build) to be able to access it. Is that expected behavior? Why is like that?

I have an app where I upload files to public/uploads and in dev mode everything works fine and then in production just saved images cannot be accessed. Am I not supposed to save images like I am doing? Please advise!

Upvotes: 4

Views: 2713

Answers (3)

user2367101
user2367101

Reputation: 141

I have the same problem when I dockerize the app.

The phrase :

I would suggest to upload files to a cloud storage like Amazon S3.

from Nikolai gave me the idea: Run a node server to read the folder.

const express = require("express");
app = express();
app.use(express.static("/path/where/images/are"));

in docker-compose.yml in the volumes section I added:

volumes:
- /path/where/images/are:/app/public

to read the shared folder

and then the images in my next.js app uses :

<img src={"https://www.server2.com/products/" + id  } alt='product'/>

The second server ( or docker in my case ) just serves the folder, and the other one ( the backend that works with next.js) uploads my images.

The other way was to restart my docker container ( that was very trashy -> hate to do that)

hope it helps !

Upvotes: 0

Kup
Kup

Reputation: 884

Might be coming late to the party here, but here's my 2cents on it

create a custom server and serve the uploads folder via express static

app.prepare().then(() => {
    const expressApp = express();
    const handle = app.getRequestHandler();

    expressApp.use(compression({ filter: shouldCompress }));
    expressApp.use(
        '/uploads',
        express.static('/root/projects/uploads', { caseSensitive: true })
    );

    expressApp.all('*', (req, res) => {
        return handle(req, res);
    });

    createServer(expressApp)
        .listen(port, (error) => {
            if(error) throw error;

            console.log(`Listening @:${port}`);
        });
});

Upvotes: 0

Nikolai Kiselev
Nikolai Kiselev

Reputation: 6603

When you start Next.js server with npm run start it reads all files in the /public directory and adds every present file to the router. If you add files after it's done the server doesn't know that something has changed there. Restarting the server without build reads the /public directory again and you can see newly added images.

In the development mode public files are not added to the router but handled as a fallback instead.

generatePublicRoutes()

Saving uploaded files to /public might be not reliable approach in production. What if the /public will be overwritten with next deploy? What if you want to scale the app and launch additional instances?

I would suggest to upload files to a cloud storage like Amazon S3.

Upvotes: 2

Related Questions