I am working with Next.js as a full-stack framework, using API route handlers in the backend.
I have stored the images in a Post method in the /uploads directory using the fs.writeFile method, and then I stored only the path to the image. This works fine I can see the image, but when I try to call it in the browser, I can't. I have tried to use and but with no success; I only get 404, 400, and in the terminal console: [0] The requested resource isn't a valid image for /uploads/images/43820915700090.jpg received text/html; charset=utf-8.
If I store the images under the /public folder, it works, but I have heard that the public folder only compiles during the build process and only serves for static content like icons and static images.
I know that I can use services like Cloudinary (I have used before) or S3 to give me a public url and then use the image , but the client doesn't want that. What should I do?
I have found the solution:
Next.js only uses the images that are stored in the public folder. However, the problem is that this folder serves the static content, so in the build process, it will copy /public
into /.next/public
, and I can't serve dynamic images from there.
To display dynamic paths that are stored in the database, I have used the fs:node
utility to read the image in a React component, and then called it in page.jsx
as shown below:
import fs from 'fs';
import path from 'path';
const MyImageComponent = ({ imageName, alt, width, height }) => {
let startTime = performance.now()
const imagePath = path.join(process.cwd(), imageName);
try {
const ext = path.extname(imagePath).slice(1);
console.log(ext)
const image = fs.readFileSync(imagePath, 'base64');
const imageUrl = `data:image/${ext};base64,${image}`;
let endTime = performance.now()
console.log(`reading the image took ${endTime - startTime} milliseconds`) // to test the time takes to render the image ===> between 0.2xx milliseconds and 1,xx second.
return <img src={imageUrl} alt={alt} width={width} height={height} />;
} catch (error) {
console.error('Error reading image file:', error);
return null;
}
};
export default MyImageComponent;
and in page.jsx I called it :
export default function Home(){
return (
<MyImageComponent imageName ="./app/images/21356888.png" />
)
}